diff --git a/client/rest/src/main/java/org/elasticsearch/client/Response.java b/client/rest/src/main/java/org/elasticsearch/client/Response.java index fe5152d956db8..cfe313c744c52 100644 --- a/client/rest/src/main/java/org/elasticsearch/client/Response.java +++ b/client/rest/src/main/java/org/elasticsearch/client/Response.java @@ -136,14 +136,14 @@ public HttpEntity getEntity() { /** * Tests if a string matches the RFC 7234 specification for warning headers. - * This assumes that the warn code is always 299 and the warn agent is always - * Elasticsearch. + * This assumes that the warn code is always 299 or 300 and the warn agent is + * always Elasticsearch. * * @param s the value of a warning header formatted according to RFC 7234 * @return {@code true} if the input string matches the specification */ private static boolean matchWarningHeaderPatternByPrefix(final String s) { - return s.startsWith("299 Elasticsearch-"); + return s.startsWith("299 Elasticsearch-") || s.startsWith("300 Elasticsearch-"); } /** diff --git a/libs/x-content/src/test/java/org/elasticsearch/xcontent/ConstructingObjectParserTests.java b/libs/x-content/src/test/java/org/elasticsearch/xcontent/ConstructingObjectParserTests.java index e6662ca3d96bc..0025faa30b0dd 100644 --- a/libs/x-content/src/test/java/org/elasticsearch/xcontent/ConstructingObjectParserTests.java +++ b/libs/x-content/src/test/java/org/elasticsearch/xcontent/ConstructingObjectParserTests.java @@ -626,8 +626,8 @@ public void testCompatibleFieldDeclarations() throws IOException { RestApiVersion.minimumSupported()); StructWithCompatibleFields o = StructWithCompatibleFields.PARSER.parse(parser, null); assertEquals(1, o.intField); - assertWarnings(false, "[struct_with_compatible_fields][1:14] " + - "Deprecated field [old_name] used, expected [new_name] instead"); + assertWarnings(false, new DeprecationWarning(DeprecationLogger.CRITICAL, "[struct_with_compatible_fields][1:14] " + + "Deprecated field [old_name] used, expected [new_name] instead")); } } diff --git a/libs/x-content/src/test/java/org/elasticsearch/xcontent/ObjectParserTests.java b/libs/x-content/src/test/java/org/elasticsearch/xcontent/ObjectParserTests.java index 278702a4bb1e0..8882d38358f0c 100644 --- a/libs/x-content/src/test/java/org/elasticsearch/xcontent/ObjectParserTests.java +++ b/libs/x-content/src/test/java/org/elasticsearch/xcontent/ObjectParserTests.java @@ -7,6 +7,7 @@ */ package org.elasticsearch.xcontent; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.xcontent.XContentParserUtils; import org.elasticsearch.core.CheckedFunction; import org.elasticsearch.core.RestApiVersion; @@ -211,7 +212,8 @@ class TestStruct { objectParser.declareField((i, v, c) -> v.test = i.text(), new ParseField("test", "old_test"), ObjectParser.ValueType.STRING); objectParser.parse(parser, s, null); assertEquals("foo", s.test); - assertWarnings(false, "[foo][1:15] Deprecated field [old_test] used, expected [test] instead"); + assertWarnings(false, new DeprecationWarning(DeprecationLogger.CRITICAL, "[foo][1:15] Deprecated field [old_test] used, " + + "expected [test] instead")); } public void testFailOnValueType() throws IOException { @@ -1072,8 +1074,8 @@ public void testCompatibleFieldDeclarations() throws IOException { RestApiVersion.minimumSupported()); StructWithCompatibleFields o = StructWithCompatibleFields.PARSER.parse(parser, null); assertEquals(1, o.intField); - assertWarnings(false, "[struct_with_compatible_fields][1:14] " + - "Deprecated field [old_name] used, expected [new_name] instead"); + assertWarnings(false, new DeprecationWarning(DeprecationLogger.CRITICAL, "[struct_with_compatible_fields][1:14] " + + "Deprecated field [old_name] used, expected [new_name] instead")); } } diff --git a/modules/ingest-geoip/src/main/java/org/elasticsearch/ingest/geoip/GeoIpProcessor.java b/modules/ingest-geoip/src/main/java/org/elasticsearch/ingest/geoip/GeoIpProcessor.java index b875c88a28a48..36de08b9a4d7e 100644 --- a/modules/ingest-geoip/src/main/java/org/elasticsearch/ingest/geoip/GeoIpProcessor.java +++ b/modules/ingest-geoip/src/main/java/org/elasticsearch/ingest/geoip/GeoIpProcessor.java @@ -470,8 +470,8 @@ public Processor create( boolean valid = metadata.isValid(currentState.metadata().settings()); if (valid && metadata.isCloseToExpiration()) { - HeaderWarning.addWarning("database [{}] was not updated for over 25 days, geoip processor will stop working if there " + - "is no update for 30 days", databaseFile); + HeaderWarning.addWarning(DeprecationLogger.CRITICAL, "database [{}] was not updated for over 25 days, geoip processor" + + " will stop working if there is no update for 30 days", databaseFile); } return valid; diff --git a/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceImplTests.java b/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceImplTests.java index 7a73db5d37081..bf7c363d94ae7 100644 --- a/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceImplTests.java +++ b/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceImplTests.java @@ -14,7 +14,10 @@ import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.BasicSessionCredentials; import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; + +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.settings.MockSecureSettings; +import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsException; import org.elasticsearch.test.ESTestCase; @@ -59,8 +62,9 @@ public void testDeprecationOfLoneAccessKey() { Ec2ClientSettings.getClientSettings(Settings.builder().setSecureSettings(secureSettings).build())).getCredentials(); assertThat(credentials.getAWSAccessKeyId(), is("aws_key")); assertThat(credentials.getAWSSecretKey(), is("")); - assertSettingDeprecationsAndWarnings(new String[]{}, - "Setting [discovery.ec2.access_key] is set but [discovery.ec2.secret_key] is not, which will be unsupported in future"); + assertSettingDeprecationsAndWarnings(new Setting[]{}, + new DeprecationWarning(DeprecationLogger.CRITICAL, "Setting [discovery.ec2.access_key] is set but " + + "[discovery.ec2.secret_key] is not, which will be unsupported in future")); } public void testDeprecationOfLoneSecretKey() { @@ -70,8 +74,9 @@ public void testDeprecationOfLoneSecretKey() { Ec2ClientSettings.getClientSettings(Settings.builder().setSecureSettings(secureSettings).build())).getCredentials(); assertThat(credentials.getAWSAccessKeyId(), is("")); assertThat(credentials.getAWSSecretKey(), is("aws_secret")); - assertSettingDeprecationsAndWarnings(new String[]{}, - "Setting [discovery.ec2.secret_key] is set but [discovery.ec2.access_key] is not, which will be unsupported in future"); + assertSettingDeprecationsAndWarnings(new Setting[]{}, + new DeprecationWarning(DeprecationLogger.CRITICAL, "Setting [discovery.ec2.secret_key] is set but " + + "[discovery.ec2.access_key] is not, which will be unsupported in future")); } public void testRejectionOfLoneSessionToken() { diff --git a/qa/logging-config/src/test/java/org/elasticsearch/common/logging/JsonLoggerTests.java b/qa/logging-config/src/test/java/org/elasticsearch/common/logging/JsonLoggerTests.java index 1c0cf3f973c9b..d15edec2698f9 100644 --- a/qa/logging-config/src/test/java/org/elasticsearch/common/logging/JsonLoggerTests.java +++ b/qa/logging-config/src/test/java/org/elasticsearch/common/logging/JsonLoggerTests.java @@ -100,7 +100,7 @@ public void testDeprecationWarnMessage() throws IOException { ); } - assertWarnings("deprecated warn message1"); + assertWarnings(true, new DeprecationWarning(Level.WARN, "deprecated warn message1")) ; } public void testDeprecatedMessageWithoutXOpaqueId() throws IOException { diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateService.java b/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateService.java index 56e41f89aa905..959f514c0256a 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateService.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateService.java @@ -24,6 +24,7 @@ import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterStateUpdateTask; import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.core.Nullable; import org.elasticsearch.common.Priority; import org.elasticsearch.common.Strings; @@ -498,7 +499,7 @@ public ClusterState addIndexTemplateV2(final ClusterState currentState, final bo .collect(Collectors.joining(",")), name); logger.warn(warning); - HeaderWarning.addWarning(warning); + HeaderWarning.addWarning(DeprecationLogger.CRITICAL, warning); } ComposableIndexTemplate finalIndexTemplate = template; @@ -828,7 +829,7 @@ static ClusterState innerPutTemplate(final ClusterState currentState, PutRequest .collect(Collectors.joining(",")), request.name); logger.warn(warning); - HeaderWarning.addWarning(warning); + HeaderWarning.addWarning(DeprecationLogger.CRITICAL, warning); } else { // Otherwise, this is a hard error, the user should use V2 index templates instead String error = String.format(Locale.ROOT, "legacy template [%s] has index patterns %s matching patterns" + diff --git a/server/src/main/java/org/elasticsearch/common/logging/HeaderWarning.java b/server/src/main/java/org/elasticsearch/common/logging/HeaderWarning.java index 1b76e7bbcc76a..ab2b263d176d9 100644 --- a/server/src/main/java/org/elasticsearch/common/logging/HeaderWarning.java +++ b/server/src/main/java/org/elasticsearch/common/logging/HeaderWarning.java @@ -8,6 +8,7 @@ package org.elasticsearch.common.logging; +import org.apache.logging.log4j.Level; import org.elasticsearch.Build; import org.elasticsearch.Version; import org.elasticsearch.common.util.concurrent.ThreadContext; @@ -32,10 +33,11 @@ public class HeaderWarning { /** * Regular expression to test if a string matches the RFC7234 specification for warning headers. This pattern assumes that the warn code - * is always 299. Further, this pattern assumes that the warn agent represents a version of Elasticsearch including the build hash. + * is always 299 or 300. Further, this pattern assumes that the warn agent represents a version of Elasticsearch including the build + * hash. */ public static final Pattern WARNING_HEADER_PATTERN = Pattern.compile( - "299 " + // warn code + "(?:299|300) " + // log level code "Elasticsearch-" + // warn agent "\\d+\\.\\d+\\.\\d+(?:-(?:alpha|beta|rc)\\d+)?(?:-SNAPSHOT)?-" + // warn agent "(?:[a-f0-9]{7}(?:[a-f0-9]{33})?|unknown) " + // warn agent @@ -53,15 +55,16 @@ public class HeaderWarning { /* * RFC7234 specifies the warning format as warn-code warn-agent "warn-text" [ "warn-date"]. Here, warn-code is a - * three-digit number with various standard warn codes specified. The warn code 299 is apt for our purposes as it represents a - * miscellaneous persistent warning (can be presented to a human, or logged, and must not be removed by a cache). The warn-agent is an - * arbitrary token; here we use the Elasticsearch version and build hash. The warn text must be quoted. The warn-date is an optional - * quoted field that can be in a variety of specified date formats; here we use RFC 1123 format. + * three-digit number with various standard warn codes specified, and is left off of this static prefix so that it can be added based + * on the log level received. The warn code will be either 299 or 300 at runtime, which are apt for our purposes as + * they represent miscellaneous persistent warnings (can be presented to a human, or logged, and must not be removed by a cache). + * The warn-agent is an arbitrary token; here we use the Elasticsearch version and build hash. The warn text must be quoted. The + * warn-date is an optional quoted field that can be in a variety of specified date formats; here we use RFC 1123 format. */ private static final String WARNING_PREFIX = String.format( Locale.ROOT, - "299 Elasticsearch-%s%s-%s", + " Elasticsearch-%s%s-%s", Version.CURRENT.toString(), Build.CURRENT.isSnapshot() ? "-SNAPSHOT" : "", Build.CURRENT.hash()); @@ -189,14 +192,15 @@ private static boolean assertWarningValue(final String s, final String warningVa * Format a warning string in the proper warning format by prepending a warn code, warn agent, wrapping the warning string in quotes, * and appending the RFC 7231 date. * + * @param level the level of the warning - Level.WARN or DeprecationLogger.CRITICAL * @param s the warning string to format * @return a warning value formatted according to RFC 7234 */ - public static String formatWarning(final String s) { + public static String formatWarning(final Level level, final String s) { // Assume that the common scenario won't have a string to escape and encode. - int length = WARNING_PREFIX.length() + s.length() + 3; + int length = WARNING_PREFIX.length() + s.length() + 6; final StringBuilder sb = new StringBuilder(length); - sb.append(WARNING_PREFIX).append(" \"").append(escapeAndEncode(s)).append("\""); + sb.append(level.intLevel() + WARNING_PREFIX).append(" \"").append(escapeAndEncode(s)).append("\""); return sb.toString(); } @@ -310,16 +314,21 @@ public static String getXOpaqueId() { .orElse(""); } - public static void addWarning(String message, Object... params) { - addWarning(THREAD_CONTEXT, message, params); + public static void addWarning(Level level, String message, Object... params) { + addWarning(THREAD_CONTEXT, level, message, params); } // package scope for testing static void addWarning(Set threadContexts, String message, Object... params) { + addWarning(threadContexts, DeprecationLogger.CRITICAL, message, params); + } + + // package scope for testing + static void addWarning(Set threadContexts, Level level, String message, Object... params) { final Iterator iterator = threadContexts.iterator(); if (iterator.hasNext()) { final String formattedMessage = LoggerMessageFormat.format(message, params); - final String warningHeaderValue = formatWarning(formattedMessage); + final String warningHeaderValue = formatWarning(level, formattedMessage); assert WARNING_HEADER_PATTERN.matcher(warningHeaderValue).matches(); assert extractWarningValueFromWarningHeader(warningHeaderValue, false) .equals(escapeAndEncode(formattedMessage)); diff --git a/server/src/main/java/org/elasticsearch/common/logging/HeaderWarningAppender.java b/server/src/main/java/org/elasticsearch/common/logging/HeaderWarningAppender.java index ad03eccdf638d..992f33a08e597 100644 --- a/server/src/main/java/org/elasticsearch/common/logging/HeaderWarningAppender.java +++ b/server/src/main/java/org/elasticsearch/common/logging/HeaderWarningAppender.java @@ -35,10 +35,10 @@ public void append(LogEvent event) { String messagePattern = esLogMessage.getMessagePattern(); Object[] arguments = esLogMessage.getArguments(); - HeaderWarning.addWarning(messagePattern, arguments); + HeaderWarning.addWarning(event.getLevel(), messagePattern, arguments); } else { final String formattedMessage = event.getMessage().getFormattedMessage(); - HeaderWarning.addWarning(formattedMessage); + HeaderWarning.addWarning(event.getLevel(), formattedMessage); } } diff --git a/server/src/main/java/org/elasticsearch/common/settings/Setting.java b/server/src/main/java/org/elasticsearch/common/settings/Setting.java index 6ca11402a4e04..d9151c9923e2b 100644 --- a/server/src/main/java/org/elasticsearch/common/settings/Setting.java +++ b/server/src/main/java/org/elasticsearch/common/settings/Setting.java @@ -99,10 +99,15 @@ public enum Property { Final, /** - * mark this setting as deprecated + * mark this setting as deprecated (critical level) */ Deprecated, + /** + * mark this setting as deprecated (warning level) + */ + DeprecatedWarning, + /** * Node scope */ @@ -169,6 +174,9 @@ private Setting(Key key, @Nullable Setting fallbackSetting, Functiontrue if this setting is deprecated, otherwise false */ - public boolean isDeprecated() { - return properties.contains(Property.Deprecated); + private boolean isDeprecated() { + return properties.contains(Property.Deprecated) || properties.contains(Property.DeprecatedWarning); + } + + private boolean isDeprecatedWarningOnly() { + return properties.contains(Property.DeprecatedWarning); } /** @@ -552,13 +564,15 @@ void checkDeprecation(Settings settings) { if (this.isDeprecated() && this.exists(settings)) { // It would be convenient to show its replacement key, but replacement is often not so simple final String key = getKey(); - List skipTheseDeprecations = settings.getAsList("deprecation.skip_deprecated_settings"); if (Regex.simpleMatch(skipTheseDeprecations, key) == false) { - Settings.DeprecationLoggerHolder.deprecationLogger - .critical(DeprecationCategory.SETTINGS, key, - "[{}] setting was deprecated in Elasticsearch and will be removed in a future release! " - + "See the breaking changes documentation for the next major version.", key); + String message = "[{}] setting was deprecated in Elasticsearch and will be removed in a future release! " + + "See the breaking changes documentation for the next major version."; + if (this.isDeprecatedWarningOnly()) { + Settings.DeprecationLoggerHolder.deprecationLogger.warn(DeprecationCategory.SETTINGS, key, message, key); + } else { + Settings.DeprecationLoggerHolder.deprecationLogger.critical(DeprecationCategory.SETTINGS, key, message, key); + } } } } diff --git a/server/src/test/java/org/elasticsearch/common/logging/HeaderWarningTests.java b/server/src/test/java/org/elasticsearch/common/logging/HeaderWarningTests.java index 9af702802a66c..73b974e6bc746 100644 --- a/server/src/test/java/org/elasticsearch/common/logging/HeaderWarningTests.java +++ b/server/src/test/java/org/elasticsearch/common/logging/HeaderWarningTests.java @@ -8,6 +8,8 @@ package org.elasticsearch.common.logging; import com.carrotsearch.randomizedtesting.generators.CodepointSetGenerator; + +import org.apache.logging.log4j.Level; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.test.ESTestCase; @@ -190,16 +192,16 @@ public void testFailsWhenRemovingUnknownThreadContext() throws IOException { public void testWarningValueFromWarningHeader() { final String s = randomAlphaOfLength(16); - final String first = HeaderWarning.formatWarning(s); + final String first = HeaderWarning.formatWarning(DeprecationLogger.CRITICAL, s); assertThat(HeaderWarning.extractWarningValueFromWarningHeader(first, false), equalTo(s)); final String withPos = "[context][1:11] Blah blah blah"; - final String formatted = HeaderWarning.formatWarning(withPos); + final String formatted = HeaderWarning.formatWarning(DeprecationLogger.CRITICAL, withPos); assertThat(HeaderWarning.extractWarningValueFromWarningHeader(formatted, true), equalTo("Blah blah blah")); final String withNegativePos = "[context][-1:-1] Blah blah blah"; - assertThat(HeaderWarning.extractWarningValueFromWarningHeader(HeaderWarning.formatWarning(withNegativePos), true), - equalTo("Blah blah blah")); + assertThat(HeaderWarning.extractWarningValueFromWarningHeader(HeaderWarning.formatWarning(DeprecationLogger.CRITICAL, + withNegativePos), true), equalTo("Blah blah blah")); } public void testEscapeBackslashesAndQuotes() { @@ -285,4 +287,22 @@ private String range(int lowerInclusive, int upperInclusive) { .toString(); } + public void testAddWarningNonDefaultLogLevel() { + final int maxWarningHeaderCount = 2; + Settings settings = Settings.builder() + .put("http.max_warning_header_count", maxWarningHeaderCount) + .build(); + ThreadContext threadContext = new ThreadContext(settings); + final Set threadContexts = Collections.singleton(threadContext); + HeaderWarning.addWarning(threadContexts, Level.WARN, "A simple message 1"); + final Map> responseHeaders = threadContext.getResponseHeaders(); + + assertThat(responseHeaders.size(), equalTo(1)); + final List responses = responseHeaders.get("Warning"); + assertThat(responses, hasSize(1)); + assertThat(responses.get(0), warningValueMatcher); + assertThat(responses.get(0), containsString("\"A simple message 1\"")); + assertThat(responses.get(0), containsString(Integer.toString(Level.WARN.intLevel()))); + } + } diff --git a/server/src/test/java/org/elasticsearch/common/settings/SettingTests.java b/server/src/test/java/org/elasticsearch/common/settings/SettingTests.java index e62ea69303944..8f6d4ebd2f818 100644 --- a/server/src/test/java/org/elasticsearch/common/settings/SettingTests.java +++ b/server/src/test/java/org/elasticsearch/common/settings/SettingTests.java @@ -12,13 +12,13 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LogEvent; import org.elasticsearch.cluster.metadata.IndexMetadata; -import org.elasticsearch.core.Tuple; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.AbstractScopedSettings.SettingUpdater; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.unit.ByteSizeUnit; import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.core.TimeValue; +import org.elasticsearch.core.Tuple; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.monitor.jvm.JvmInfo; import org.elasticsearch.test.ESTestCase; @@ -152,7 +152,7 @@ public void testMemorySize() { assertEquals(new ByteSizeValue(12), value.get()); assertTrue(settingUpdater.apply(Settings.builder().put("a.byte.size", "20%").build(), Settings.EMPTY)); - assertEquals(new ByteSizeValue((int) (JvmInfo.jvmInfo().getMem().getHeapMax().getBytes() * 0.2)), value.get()); + assertEquals(new ByteSizeValue((long) (JvmInfo.jvmInfo().getMem().getHeapMax().getBytes() * 0.2)), value.get()); } public void testSimpleUpdate() { @@ -1260,6 +1260,27 @@ public void testDynamicTest() { } public void testCheckForDeprecation() { + final String criticalSettingName = "foo.bar"; + final String warningSettingName = "foo.foo"; + final String settingValue = "blat"; + final Setting undeprecatedSetting1 = Setting.simpleString(criticalSettingName, settingValue); + final Setting undeprecatedSetting2 = Setting.simpleString(warningSettingName, settingValue); + final Settings settings = Settings.builder() + .put(criticalSettingName, settingValue) + .put(warningSettingName, settingValue).build(); + undeprecatedSetting1.checkDeprecation(settings); + undeprecatedSetting2.checkDeprecation(settings); + ensureNoWarnings(); + final Setting criticalDeprecatedSetting = Setting.simpleString(criticalSettingName, settingValue, Property.Deprecated); + criticalDeprecatedSetting.checkDeprecation(settings); + assertSettingDeprecationsAndWarnings(new Setting[]{ criticalDeprecatedSetting }); + final Setting deprecatedSettingWarningOnly = + Setting.simpleString(warningSettingName, settingValue, Property.DeprecatedWarning); + deprecatedSettingWarningOnly.checkDeprecation(settings); + assertSettingDeprecationsAndWarnings(new Setting[]{ deprecatedSettingWarningOnly }); + } + + public void testCheckForDeprecationWithSkipSetting() { final String settingName = "foo.bar"; final String settingValue = "blat"; final Setting setting = Setting.simpleString(settingName, settingValue); @@ -1275,4 +1296,13 @@ public void testCheckForDeprecation() { deprecatedSetting.checkDeprecation(settingsWithSkipDeprecationSetting); ensureNoWarnings(); } + + public void testDeprecationPropertyValidation() { + final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> + Setting.boolSetting( + "a.bool.setting", + true, + Property.Deprecated, + Property.DeprecatedWarning)); + } } diff --git a/server/src/test/java/org/elasticsearch/common/util/concurrent/ThreadContextTests.java b/server/src/test/java/org/elasticsearch/common/util/concurrent/ThreadContextTests.java index b0904729bf060..35bc681788f6e 100644 --- a/server/src/test/java/org/elasticsearch/common/util/concurrent/ThreadContextTests.java +++ b/server/src/test/java/org/elasticsearch/common/util/concurrent/ThreadContextTests.java @@ -8,6 +8,7 @@ package org.elasticsearch.common.util.concurrent; import org.elasticsearch.common.io.stream.BytesStreamOutput; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.logging.HeaderWarning; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.test.ESTestCase; @@ -266,11 +267,11 @@ public void testResponseHeaders() { threadContext.addResponseHeader("foo", "bar"); } - final String value = HeaderWarning.formatWarning("qux"); + final String value = HeaderWarning.formatWarning(DeprecationLogger.CRITICAL, "qux"); threadContext.addResponseHeader("baz", value, s -> HeaderWarning.extractWarningValueFromWarningHeader(s, false)); // pretend that another thread created the same response at a different time if (randomBoolean()) { - final String duplicateValue = HeaderWarning.formatWarning("qux"); + final String duplicateValue = HeaderWarning.formatWarning(DeprecationLogger.CRITICAL, "qux"); threadContext.addResponseHeader("baz", duplicateValue, s -> HeaderWarning.extractWarningValueFromWarningHeader(s, false)); } diff --git a/test/external-modules/error-query/src/main/java/org/elasticsearch/test/errorquery/ErrorQueryBuilder.java b/test/external-modules/error-query/src/main/java/org/elasticsearch/test/errorquery/ErrorQueryBuilder.java index 15a6f50244cb0..5d6f69aca03b5 100644 --- a/test/external-modules/error-query/src/main/java/org/elasticsearch/test/errorquery/ErrorQueryBuilder.java +++ b/test/external-modules/error-query/src/main/java/org/elasticsearch/test/errorquery/ErrorQueryBuilder.java @@ -12,6 +12,7 @@ import org.apache.lucene.search.Query; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.logging.HeaderWarning; import org.elasticsearch.index.query.AbstractQueryBuilder; import org.elasticsearch.index.query.SearchExecutionContext; @@ -81,7 +82,7 @@ protected Query doToQuery(SearchExecutionContext context) throws IOException { } final String header = "[" + context.index().getName() + "][" + context.getShardId() + "]"; if (error.getErrorType() == IndexError.ERROR_TYPE.WARNING) { - HeaderWarning.addWarning(header + " " + error.getMessage()); + HeaderWarning.addWarning(DeprecationLogger.CRITICAL, header + " " + error.getMessage()); return new MatchAllDocsQuery(); } else { throw new RuntimeException(header + " " + error.getMessage()); diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java index d1cbe38754cfa..786b991a8a8f9 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java @@ -18,6 +18,7 @@ import com.carrotsearch.randomizedtesting.generators.RandomPicks; import com.carrotsearch.randomizedtesting.generators.RandomStrings; import com.carrotsearch.randomizedtesting.rules.TestRuleAdapter; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -40,19 +41,14 @@ import org.elasticsearch.client.Requests; import org.elasticsearch.cluster.ClusterModule; import org.elasticsearch.cluster.metadata.IndexMetadata; -import org.elasticsearch.core.CheckedRunnable; -import org.elasticsearch.core.RestApiVersion; -import org.elasticsearch.core.SuppressForbidden; import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.core.Tuple; -import org.elasticsearch.core.PathUtils; -import org.elasticsearch.core.PathUtilsForTesting; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.NamedWriteable; import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.logging.HeaderWarning; import org.elasticsearch.common.logging.HeaderWarningAppender; import org.elasticsearch.common.logging.LogConfigurator; @@ -65,16 +61,13 @@ import org.elasticsearch.common.util.MockBigArrays; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; -import org.elasticsearch.xcontent.MediaType; -import org.elasticsearch.xcontent.NamedXContentRegistry; -import org.elasticsearch.xcontent.ToXContent; -import org.elasticsearch.xcontent.XContent; -import org.elasticsearch.xcontent.XContentBuilder; -import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentHelper; -import org.elasticsearch.xcontent.XContentParser; -import org.elasticsearch.xcontent.XContentParser.Token; -import org.elasticsearch.xcontent.XContentType; +import org.elasticsearch.core.CheckedRunnable; +import org.elasticsearch.core.PathUtils; +import org.elasticsearch.core.PathUtilsForTesting; +import org.elasticsearch.core.RestApiVersion; +import org.elasticsearch.core.SuppressForbidden; +import org.elasticsearch.core.Tuple; import org.elasticsearch.env.Environment; import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.env.TestEnvironment; @@ -100,6 +93,15 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.LeakTracker; import org.elasticsearch.transport.nio.MockNioTransportPlugin; +import org.elasticsearch.xcontent.MediaType; +import org.elasticsearch.xcontent.NamedXContentRegistry; +import org.elasticsearch.xcontent.ToXContent; +import org.elasticsearch.xcontent.XContent; +import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xcontent.XContentFactory; +import org.elasticsearch.xcontent.XContentParser; +import org.elasticsearch.xcontent.XContentParser.Token; +import org.elasticsearch.xcontent.XContentType; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -439,48 +441,70 @@ protected List filteredWarnings() { /** * Convenience method to assert warnings for settings deprecations and general deprecation warnings. - * * @param settings the settings that are expected to be deprecated * @param warnings other expected general deprecation warnings */ - protected final void assertSettingDeprecationsAndWarnings(final Setting[] settings, final String... warnings) { - assertSettingDeprecationsAndWarnings(Arrays.stream(settings).map(Setting::getKey).toArray(String[]::new), warnings); - } - - protected final void assertSettingDeprecationsAndWarnings(final String[] settings, final String... warnings) { + protected final void assertSettingDeprecationsAndWarnings(final Setting[] settings, final DeprecationWarning... warnings) { assertWarnings( - Stream.concat( - Arrays - .stream(settings) - .map(k -> "[" + k + "] setting was deprecated in Elasticsearch and will be removed in a future release! " + - "See the breaking changes documentation for the next major version."), - Arrays.stream(warnings)) - .toArray(String[]::new)); + true, + Stream.concat( + Arrays + .stream(settings) + .map(setting -> { + String warningMessage = String.format( + Locale.ROOT, "[%s] setting was deprecated in Elasticsearch and will be " + + "removed in a future release! See the breaking changes documentation for the next major version.", + setting.getKey()); + return new DeprecationWarning(setting.getProperties().contains(Setting.Property.Deprecated) ? + DeprecationLogger.CRITICAL : Level.WARN, warningMessage); + }), + Arrays.stream(warnings)) + .toArray(DeprecationWarning[]::new)); } + /** + * Convenience method to assert warnings for settings deprecations and general deprecation warnings. All warnings passed to this method + * are assumed to be at DeprecationLogger.CRITICAL level. + * @param expectedWarnings expected general deprecation warnings. + */ protected final void assertWarnings(String... expectedWarnings) { - assertWarnings(true, expectedWarnings); + assertWarnings(true, Arrays.stream(expectedWarnings).map(expectedWarning -> new DeprecationWarning(DeprecationLogger.CRITICAL, + expectedWarning)).toArray(DeprecationWarning[]::new)); } - protected final void assertWarnings(boolean stripXContentPosition, String... expectedWarnings) { + protected final void assertWarnings(boolean stripXContentPosition, DeprecationWarning... expectedWarnings) { if (enableWarningsCheck() == false) { throw new IllegalStateException("unable to check warning headers if the test is not set to do so"); } try { - final List actualWarnings = threadContext.getResponseHeaders().get("Warning"); + final List actualWarningStrings = threadContext.getResponseHeaders().get("Warning"); if (expectedWarnings == null || expectedWarnings.length == 0) { - assertNull("expected 0 warnings, actual: " + actualWarnings, actualWarnings); + assertNull("expected 0 warnings, actual: " + actualWarningStrings, actualWarningStrings); } else { - assertNotNull("no warnings, expected: " + Arrays.asList(expectedWarnings), actualWarnings); - final Set actualWarningValues = - actualWarnings.stream().map(s -> HeaderWarning.extractWarningValueFromWarningHeader(s, stripXContentPosition)) + assertNotNull("no warnings, expected: " + Arrays.asList(expectedWarnings), actualWarningStrings); + final Set actualDeprecationWarnings = + actualWarningStrings.stream() + .map(warningString -> { + String warningText = HeaderWarning.extractWarningValueFromWarningHeader(warningString, stripXContentPosition); + final Level level; + if (warningString.startsWith(Integer.toString(DeprecationLogger.CRITICAL.intLevel()))) { + level = DeprecationLogger.CRITICAL; + } else if (warningString.startsWith(Integer.toString(Level.WARN.intLevel()))) { + level = Level.WARN; + } else { + throw new IllegalArgumentException("Unknown level in deprecation message " + warningString); + } + return new DeprecationWarning(level, warningText); + }) .collect(Collectors.toSet()); - for (String msg : expectedWarnings) { - assertThat(actualWarningValues, hasItem(HeaderWarning.escapeAndEncode(msg))); + for (DeprecationWarning expectedWarning : expectedWarnings) { + DeprecationWarning escapedExpectedWarning = new DeprecationWarning(expectedWarning.level, + HeaderWarning.escapeAndEncode(expectedWarning.message)); + assertThat(actualDeprecationWarnings, hasItem(escapedExpectedWarning)); } - assertEquals("Expected " + expectedWarnings.length + " warnings but found " + actualWarnings.size() + "\nExpected: " - + Arrays.asList(expectedWarnings) + "\nActual: " + actualWarnings, - expectedWarnings.length, actualWarnings.size() + assertEquals("Expected " + expectedWarnings.length + " warnings but found " + actualWarningStrings.size() + "\nExpected: " + + Arrays.asList(expectedWarnings) + "\nActual: " + actualWarningStrings, + expectedWarnings.length, actualWarningStrings.size() ); } } finally { @@ -1555,4 +1579,31 @@ protected static InetAddress randomIp(boolean v4) { throw new AssertionError(); } } + + public static final class DeprecationWarning { + private final Level level; + private final String message; + public DeprecationWarning(Level level, String message) { + this.level = level; + this.message = message; + } + + @Override + public int hashCode() { + return Objects.hash(level, message); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DeprecationWarning that = (DeprecationWarning) o; + return Objects.equals(level, that.level) && Objects.equals(message, that.message); + } + + @Override + public String toString() { + return String.format(Locale.ROOT, "%s (%s): %s", level.name(), level.intLevel(), message); + } + } } diff --git a/test/framework/src/test/java/org/elasticsearch/test/rest/yaml/section/DoSectionTests.java b/test/framework/src/test/java/org/elasticsearch/test/rest/yaml/section/DoSectionTests.java index c5a83db87dabc..3274608c01233 100644 --- a/test/framework/src/test/java/org/elasticsearch/test/rest/yaml/section/DoSectionTests.java +++ b/test/framework/src/test/java/org/elasticsearch/test/rest/yaml/section/DoSectionTests.java @@ -13,6 +13,7 @@ import org.elasticsearch.client.Node; import org.elasticsearch.client.NodeSelector; import org.elasticsearch.common.ParsingException; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.logging.HeaderWarning; import org.elasticsearch.xcontent.XContentLocation; import org.elasticsearch.xcontent.XContentParser; @@ -51,10 +52,10 @@ public void testWarningHeaders() { section.checkWarningHeaders(emptyList()); } - final String testHeader = HeaderWarning.formatWarning("test"); - final String anotherHeader = HeaderWarning.formatWarning("another \"with quotes and \\ backslashes\""); - final String someMoreHeader = HeaderWarning.formatWarning("some more"); - final String catHeader = HeaderWarning.formatWarning("cat"); + final String testHeader = HeaderWarning.formatWarning(DeprecationLogger.CRITICAL, "test"); + final String anotherHeader = HeaderWarning.formatWarning(DeprecationLogger.CRITICAL, "another \"with quotes and \\ backslashes\""); + final String someMoreHeader = HeaderWarning.formatWarning(DeprecationLogger.CRITICAL, "some more"); + final String catHeader = HeaderWarning.formatWarning(DeprecationLogger.CRITICAL, "cat"); // Any warning headers fail { final DoSection section = new DoSection(new XContentLocation(1, 1)); @@ -129,11 +130,12 @@ public void testWarningHeaders() { public void testWarningHeadersRegex() { - final String testHeader = HeaderWarning.formatWarning("test"); - final String realisticTestHeader = HeaderWarning.formatWarning("index template [my-it] has index patterns [test-*] matching " + - "patterns from existing older templates [global] with patterns (global => [*]); this template [my-it] will take " + - "precedence during new index creation"); - final String testHeaderWithQuotesAndBackslashes = HeaderWarning.formatWarning("test \"with quotes and \\ backslashes\""); + final String testHeader = HeaderWarning.formatWarning(DeprecationLogger.CRITICAL, "test"); + final String realisticTestHeader = HeaderWarning.formatWarning(DeprecationLogger.CRITICAL, "index template [my-it] has index " + + "patterns [test-*] matching patterns from existing older templates [global] with patterns (global => [*]); this template " + + "[my-it] will take precedence during new index creation"); + final String testHeaderWithQuotesAndBackslashes = + HeaderWarning.formatWarning(DeprecationLogger.CRITICAL, "test \"with quotes and \\ backslashes\""); //require header and it matches (basic example) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java index eb22ee0b03b9c..6c4d09de2a414 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java @@ -7,6 +7,7 @@ package org.elasticsearch.license; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.logging.HeaderWarning; import org.elasticsearch.common.logging.LoggerMessageFormat; import org.elasticsearch.common.settings.Settings; @@ -485,7 +486,7 @@ boolean isAllowed(LicensedFeature feature) { void checkExpiry() { String warning = status.expiryWarning; if (warning != null) { - HeaderWarning.addWarning(warning); + HeaderWarning.addWarning(DeprecationLogger.CRITICAL, warning); } } diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/action/TransportPutTrainedModelAliasAction.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/action/TransportPutTrainedModelAliasAction.java index a9871c6ed50bd..ceb50f59e073f 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/action/TransportPutTrainedModelAliasAction.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/action/TransportPutTrainedModelAliasAction.java @@ -21,6 +21,7 @@ import org.elasticsearch.cluster.metadata.Metadata; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.logging.HeaderWarning; import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.license.LicenseUtils; @@ -171,7 +172,7 @@ protected void masterOperation( oldModelId); auditor.warning(oldModelId, warning); logger.warn("[{}] {}", oldModelId, warning); - HeaderWarning.addWarning(warning); + HeaderWarning.addWarning(DeprecationLogger.CRITICAL, warning); } } clusterService.submitStateUpdateTask("update-model-alias", new AckedClusterStateUpdateTask(request, listener) { diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/action/TransportStartDataFrameAnalyticsAction.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/action/TransportStartDataFrameAnalyticsAction.java index 2df840449db61..d29c128f307af 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/action/TransportStartDataFrameAnalyticsAction.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/action/TransportStartDataFrameAnalyticsAction.java @@ -27,6 +27,7 @@ import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Strings; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.logging.HeaderWarning; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.ByteSizeValue; @@ -221,7 +222,7 @@ private void estimateMemoryUsageAndUpdateMemoryTracker(StartContext startContext expectedMemoryWithoutDisk); auditor.warning(jobId, warning); logger.warn("[{}] {}", jobId, warning); - HeaderWarning.addWarning(warning); + HeaderWarning.addWarning(DeprecationLogger.CRITICAL, warning); } // Refresh memory requirement for jobs memoryTracker.addDataFrameAnalyticsJobMemoryAndRefreshAllOthers( diff --git a/x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/action/TransportPreviewTransformAction.java b/x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/action/TransportPreviewTransformAction.java index bb43eb1226058..d5dc6012a479a 100644 --- a/x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/action/TransportPreviewTransformAction.java +++ b/x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/action/TransportPreviewTransformAction.java @@ -22,6 +22,7 @@ import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.logging.HeaderWarning; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.xcontent.ToXContent; @@ -242,7 +243,7 @@ private void getPreview( ); List warnings = TransformConfigLinter.getWarnings(function, source, syncConfig); - warnings.forEach(HeaderWarning::addWarning); + warnings.forEach(warning -> HeaderWarning.addWarning(DeprecationLogger.CRITICAL, warning)); listener.onResponse(new Response(docs, generatedDestIndexSettings)); }, listener::onFailure); @@ -255,7 +256,7 @@ private void getPreview( Clock.systemUTC() ); List warnings = TransformConfigLinter.getWarnings(function, source, syncConfig); - warnings.forEach(HeaderWarning::addWarning); + warnings.forEach(warning -> HeaderWarning.addWarning(DeprecationLogger.CRITICAL, warning)); listener.onResponse(new Response(docs, generatedDestIndexSettings)); } else { List> results = docs.stream().map(doc -> { diff --git a/x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/transforms/TransformNodes.java b/x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/transforms/TransformNodes.java index bf86cec56631b..ff44565818fbc 100644 --- a/x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/transforms/TransformNodes.java +++ b/x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/transforms/TransformNodes.java @@ -16,6 +16,7 @@ import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.logging.HeaderWarning; import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.settings.Settings; @@ -160,7 +161,7 @@ public static boolean hasAnyTransformNode(DiscoveryNodes nodes) { public static void warnIfNoTransformNodes(ClusterState clusterState) { if (TransformMetadata.getTransformMetadata(clusterState).isResetMode() == false) { if (hasAnyTransformNode(clusterState.getNodes()) == false) { - HeaderWarning.addWarning(TransformMessages.REST_WARN_NO_TRANSFORM_NODES); + HeaderWarning.addWarning(DeprecationLogger.CRITICAL, TransformMessages.REST_WARN_NO_TRANSFORM_NODES); } } }