diff --git a/src/main/java/ru/yandex/metrika/clickhouse/CHConnectionImpl.java b/src/main/java/ru/yandex/metrika/clickhouse/CHConnectionImpl.java index 992ab1ae47ed690a0db2981f2f70ef490cadfee7..a4057da13041fd85f89ebdf3a1f12ce6c2af79e6 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/CHConnectionImpl.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/CHConnectionImpl.java @@ -2,6 +2,7 @@ package ru.yandex.metrika.clickhouse; import org.apache.http.impl.client.CloseableHttpClient; import ru.yandex.metrika.clickhouse.copypaste.CHProperties; +import ru.yandex.metrika.clickhouse.except.ClickhouseUnhandledException; import ru.yandex.metrika.clickhouse.util.CHHttpClientBuilder; import ru.yandex.metrika.clickhouse.util.LogProxy; import ru.yandex.metrika.clickhouse.util.Logger; @@ -117,7 +118,7 @@ public class CHConnectionImpl implements CHConnection { httpclient.close(); closed = true; } catch (IOException e) { - throw new CHException("HTTP client close exception", e); + throw new ClickhouseUnhandledException("HTTP client close exception", e, dataSource.getHost(), dataSource.getPort()); } } diff --git a/src/main/java/ru/yandex/metrika/clickhouse/CHException.java b/src/main/java/ru/yandex/metrika/clickhouse/CHException.java index de3e900bc1da614c83a1c63ddc492ac6294c7b59..92d6a5630bdceebb194872035b5d707a8814eb7a 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/CHException.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/CHException.java @@ -7,28 +7,11 @@ import java.sql.SQLException; */ public class CHException extends SQLException { - - public CHException(String reason) { - super(reason); - } - - public CHException(String reason, int vendorCode) { - super(reason, null, vendorCode); - } - - public CHException(String reason, Throwable cause) { - super(reason, cause); - } - - public CHException(Throwable cause, String host, int port) { - super("ClickHouse exception, host: " + host + ", port: " + port, cause); - } - public CHException(int code, Throwable cause, String host, int port) { - super("ClickHouse exception, code: " + code + ", host: " + host + ", port: " + port, cause); + super("ClickHouse exception, code: " + code + ", host: " + host + ", port: " + port, null, code, cause); } - public CHException(String message, Throwable cause, String host, int port) { - super("ClickHouse exception, message: " + message + ", host: " + host + ", port: " + port, cause); + public CHException(int code, String message, Throwable cause, String host, int port) { + super("ClickHouse exception, message: " + message + ", host: " + host + ", port: " + port, null, code, cause); } } diff --git a/src/main/java/ru/yandex/metrika/clickhouse/CHStatementImpl.java b/src/main/java/ru/yandex/metrika/clickhouse/CHStatementImpl.java index 94d8cbf4718ddafb44849f9481248a4a3e32414a..afddcb257904cb099c8470b8e094d10110cba8f0 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/CHStatementImpl.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/CHStatementImpl.java @@ -74,8 +74,9 @@ public class CHStatementImpl implements CHStatement { ); currentResult.setMaxRows(maxRows); return currentResult; - } catch (Exception e) { - throw new RuntimeException(e); + } catch (Exception e){ + CopypasteUtils.close(is); + throw ClickhouseExceptionSpecifier.specify(e, source.getHost(), source.getPort()); } } @@ -105,7 +106,7 @@ public class CHStatementImpl implements CHStatement { } catch (IOException e) { throw new RuntimeException(e); } finally { - if (is != null) try {is.close();} catch (IOException ignored) { } + CopypasteUtils.close(is); } } @@ -117,7 +118,7 @@ public class CHStatementImpl implements CHStatement { //noinspection StatementWithEmptyBody while (rs.next()) {} } finally { - try { if (rs != null) rs.close(); } catch (Exception ignored) {} + CopypasteUtils.close(rs); } return 1; } @@ -419,7 +420,7 @@ public class CHStatementImpl implements CHStatement { } chMessage = CopypasteUtils.toString(messageStream); } catch (IOException e) { - chMessage = "error while read response "+ e.getMessage(); + chMessage = "error while read response " + e.getMessage(); } EntityUtils.consumeQuietly(entity); throw ClickhouseExceptionSpecifier.specify(chMessage, source.getHost(), source.getPort()); @@ -432,12 +433,14 @@ public class CHStatementImpl implements CHStatement { is = baos.convertToInputStream(); } return is; - } catch (IOException e) { + } catch (CHException e){ + throw e; + } catch (Exception e) { log.info("Error during connection to " + source + ", reporting failure to data source, message: " + e.getMessage()); EntityUtils.consumeQuietly(entity); - try { if (is != null) is.close(); } catch (IOException ignored) { } + CopypasteUtils.close(is); log.info("Error sql: " + sql); - throw new CHException("Unknown IO exception", e); + throw ClickhouseExceptionSpecifier.specify(e, source.getHost(), source.getPort()); } } diff --git a/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseApiException.java b/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseApiException.java index 67e36dfb173e65b3d012814f85598e5871d80ad4..3d91d75aabc6e2fd930d305e441a9cc602f41025 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseApiException.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseApiException.java @@ -7,8 +7,6 @@ import ru.yandex.metrika.clickhouse.CHException; * @since 16.02.15 */ public class ClickhouseApiException extends CHException { - public static final String MESSAGE = - "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ðµ может быть обработан из-за внутренней ошибки. Мы проанализируем и поÑтараемÑÑ ÑƒÑтранить причину как можно быÑтрее. ПожалуйÑта, не отправлÑйте Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾."; public ClickhouseApiException(Integer code, Throwable cause, String host, int port) { super(code, cause, host, port); diff --git a/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseDbException.java b/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseDbException.java index 03fa2a2b46450c95c409ee0ac22fa8a18a2cef46..d8655c7aff975ca0b926e22beea908bd43f5055f 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseDbException.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseDbException.java @@ -7,8 +7,6 @@ import ru.yandex.metrika.clickhouse.CHException; * @since 16.02.15 */ public class ClickhouseDbException extends CHException { - public static final String MESSAGE = - "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ðµ может быть обработан в данный момент из-за возроÑшей нагрузки. ПожалуйÑта, отправьте Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾ через неÑколько минут."; public ClickhouseDbException(Integer code, Throwable cause, String host, int port) { super(code, cause, host, port); diff --git a/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseErrorCode.java b/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseErrorCode.java index 5c2a7557e797005b920cf54f7e48fbc08d86bef8..8ed2963a2487b3f8f5a014582b6b872ca230feae 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseErrorCode.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseErrorCode.java @@ -29,7 +29,8 @@ public enum ClickhouseErrorCode { NETWORK_ERROR (210), EMPTY_QUERY (211), MEMORY_LIMIT_EXCEEDED (241), - POCO_EXCEPTION (1000); + POCO_EXCEPTION (1000), + UNKNOWN_EXCEPTION (1002); public final Integer code; diff --git a/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseExceptionSpecifier.java b/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseExceptionSpecifier.java index 43b51ff57d230615406bda832e562936492f1176..56c3b489b6e90f29ed0200c8d15e6334b7a6e445 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseExceptionSpecifier.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseExceptionSpecifier.java @@ -5,11 +5,13 @@ import ru.yandex.metrika.clickhouse.CHException; import ru.yandex.metrika.clickhouse.util.CopypasteUtils; import ru.yandex.metrika.clickhouse.util.Logger; +import java.net.ConnectException; import java.net.SocketTimeoutException; import java.util.Collections; import java.util.HashMap; import java.util.Map; + /** * @author lemmsh * @since 7/17/14 @@ -86,22 +88,33 @@ public final class ClickhouseExceptionSpecifier { * Очень надеемÑÑ, что кто-то будет в Ñти теÑÑ‚Ñ‹ Ñмотреть и актуализировать парÑинг. */ public static CHException specify(String clickhouseMessage, Throwable cause, String host, int port) { - if (CopypasteUtils.isBlank(clickhouseMessage) && cause != null) { + if (CopypasteUtils.isEmpty(clickhouseMessage) && cause != null) { if (cause instanceof SocketTimeoutException) - return new ClickhouseQueryException(ClickhouseErrorCode.SOCKET_TIMEOUT.code, cause, host, port); - else if (cause instanceof ConnectTimeoutException) - return new ClickhouseQueryException(ClickhouseErrorCode.NETWORK_ERROR.code, cause, host, port); + // еÑли приехал STE, то Ñкажем, что Ñто Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ð»Ð¾Ñ…Ð¾Ð¹, Ñто не то же Ñамое, что SOCKET_TIMEOUT от кликхауÑа + // Ñ…Ð¾Ñ‚Ñ Ñто также может значить падающий кликхауÑ, поÑмотрим что выглÑдит правдоподобнее + return new ClickhouseQueryException(ClickhouseErrorCode.TIMEOUT_EXCEEDED.code, cause, host, port); + else if (cause instanceof ConnectTimeoutException || cause instanceof ConnectException) + // не Ñмогли ÑоединитьÑÑ Ñ ÐºÐ»Ð¸ÐºÑ…Ð°ÑƒÑом за connectTimeout - в принципе, может быть никто не виноват + // Ñреди наших ÑущноÑтей (query/api/db), но обвинить кого-то надо, и Ñто будет db + return new ClickhouseDbException(ClickhouseErrorCode.NETWORK_ERROR.code, cause, host, port); else return new ClickhouseUnhandledException(cause, host, port); } try { - // быÑтро и опаÑно - int code = Integer.parseInt(clickhouseMessage.substring(clickhouseMessage.indexOf(' ') + 1, clickhouseMessage.indexOf(','))); + int code; + if(clickhouseMessage.startsWith("Poco::Exception. Code: 1000, ")) { + code = 1000; + } else { + // быÑтро и опаÑно Code: 175, e.displayText() = DB::Exception: + code = Integer.parseInt(clickhouseMessage.substring(clickhouseMessage.indexOf(' ') + 1, clickhouseMessage.indexOf(','))); + } // ошибку в изначальном виде вÑе-таки укажем Throwable messageHolder = cause != null ? cause : new Throwable(clickhouseMessage); - ClickhouseExceptionFactory clickhouseExceptionFactory = FACTORIES.get(code); - if (clickhouseExceptionFactory == null) clickhouseExceptionFactory = DEFAULT_FACTORY; - return clickhouseExceptionFactory.create(code, messageHolder, host, port); + if (FACTORIES.containsKey(code)) { + return FACTORIES.get(code).create(code, messageHolder, host, port); + } else { + return DEFAULT_FACTORY.create(code, messageHolder, host, port); + } } catch (Exception e) { log.error("Unsupported clickhouse error format, please fix ClickhouseExceptionSpecifier, message: " + clickhouseMessage + ", error: " + e.getMessage()); @@ -113,4 +126,4 @@ public final class ClickhouseExceptionSpecifier { CHException create(Integer code, Throwable cause, String host, int port); } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseQueryException.java b/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseQueryException.java index c2625935359cfd45b69746de93b1aa878042641a..3427f1c85e7c4682943e1a165f568eac039c849b 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseQueryException.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseQueryException.java @@ -8,8 +8,6 @@ import ru.yandex.metrika.clickhouse.CHException; * @since 16.02.15 */ public class ClickhouseQueryException extends CHException { - public static final String MESSAGE = - "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ñлишком Ñложный и не может быть обработан. ПожалуйÑта, уменьшите интервал дат запроÑа либо включите/уменьшите Ñемплирование и повторите запроÑ."; public ClickhouseQueryException(Integer code, Throwable cause, String host, int port) { super(code, cause, host, port); diff --git a/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseUnhandledException.java b/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseUnhandledException.java index e47d500970e180bf1cc1f01dad04f4e0c279ea76..016a6805efbec8224b2d094959e295f63f2544f8 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseUnhandledException.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/except/ClickhouseUnhandledException.java @@ -7,16 +7,14 @@ import ru.yandex.metrika.clickhouse.CHException; * @since 16.02.15 */ public class ClickhouseUnhandledException extends CHException { - public static final String MESSAGE = - "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ðµ может быть обработан по неизвеÑтной причине. Мы проанализируем и поÑтараемÑÑ ÑƒÑтранить причину как можно быÑтрее. ПожалуйÑта, отправьте Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾ через неÑколько минут."; public ClickhouseUnhandledException(Throwable cause, String host, int port) { - super(cause, host, port); + super(ClickhouseErrorCode.UNKNOWN_EXCEPTION.code, cause, host, port); } public ClickhouseUnhandledException(String message, Throwable cause, String host, int port) { - super(message, cause, host, port); + super(ClickhouseErrorCode.UNKNOWN_EXCEPTION.code, message, cause, host, port); } public ClickhouseUnhandledException(Integer code, Throwable cause, String host, int port) { diff --git a/src/main/java/ru/yandex/metrika/clickhouse/util/CopypasteUtils.java b/src/main/java/ru/yandex/metrika/clickhouse/util/CopypasteUtils.java index 681c6e19503aeacd93dc20c90adc428865606275..0059b0c1431f2168ff14573552fb4a242536040b 100644 --- a/src/main/java/ru/yandex/metrika/clickhouse/util/CopypasteUtils.java +++ b/src/main/java/ru/yandex/metrika/clickhouse/util/CopypasteUtils.java @@ -1,10 +1,9 @@ package ru.yandex.metrika.clickhouse.util; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.*; import java.nio.charset.Charset; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -14,6 +13,7 @@ import java.util.List; */ public class CopypasteUtils { + private static final Logger log = Logger.of(CopypasteUtils.class); public static final Charset UTF_8 = Charset.forName("UTF-8"); /////// Metrika code ////// @@ -191,4 +191,22 @@ public class CopypasteUtils { return total; } + public static void close(Closeable closeable){ + if (closeable == null) return; + try{ + closeable.close(); + } catch (IOException e){ + log.error("can not close stream: " + e.getMessage()); + } + } + + public static void close(ResultSet rs){ + if (rs == null) return; + try{ + rs.close(); + } catch (SQLException e){ + log.error("can not close resultset: " + e.getMessage()); + } + } + }