diff --git a/client/rest/src/test/java/org/elasticsearch/client/RestClientSingleHostTests.java b/client/rest/src/test/java/org/elasticsearch/client/RestClientSingleHostTests.java index fa5e9bcc6b43c..44264a99c4db0 100644 --- a/client/rest/src/test/java/org/elasticsearch/client/RestClientSingleHostTests.java +++ b/client/rest/src/test/java/org/elasticsearch/client/RestClientSingleHostTests.java @@ -519,7 +519,7 @@ private void assertDeprecationWarnings(List warningHeaderTexts, List> getTokenizers() { throw new IllegalArgumentException("The [nGram] tokenizer name was deprecated in 7.6. " + "Please use the tokenizer name to [ngram] for indices created in versions 8 or higher instead."); } else if (indexSettings.getIndexVersionCreated().onOrAfter(org.elasticsearch.Version.V_7_6_0)) { - deprecationLogger.deprecatedAndMaybeLog("nGram_tokenizer_deprecation", - "The [nGram] tokenizer name is deprecated and will be removed in a future version. " - + "Please change the tokenizer name to [ngram] instead."); + deprecationLogger.deprecate("nGram_tokenizer_deprecation", + "The [nGram] tokenizer name is deprecated and will be removed in a future version. " + + "Please change the tokenizer name to [ngram] instead."); } return new NGramTokenizerFactory(indexSettings, environment, name, settings); }); @@ -359,9 +359,9 @@ public Map> getTokenizers() { throw new IllegalArgumentException("The [edgeNGram] tokenizer name was deprecated in 7.6. " + "Please use the tokenizer name to [edge_nGram] for indices created in versions 8 or higher instead."); } else if (indexSettings.getIndexVersionCreated().onOrAfter(org.elasticsearch.Version.V_7_6_0)) { - deprecationLogger.deprecatedAndMaybeLog("edgeNGram_tokenizer_deprecation", - "The [edgeNGram] tokenizer name is deprecated and will be removed in a future version. " - + "Please change the tokenizer name to [edge_ngram] instead."); + deprecationLogger.deprecate("edgeNGram_tokenizer_deprecation", + "The [edgeNGram] tokenizer name is deprecated and will be removed in a future version. " + + "Please change the tokenizer name to [edge_ngram] instead."); } return new EdgeNGramTokenizerFactory(indexSettings, environment, name, settings); }); @@ -552,9 +552,9 @@ public List getPreConfiguredTokenizers() { throw new IllegalArgumentException("The [nGram] tokenizer name was deprecated in 7.6. " + "Please use the tokenizer name to [ngram] for indices created in versions 8 or higher instead."); } else if (version.onOrAfter(org.elasticsearch.Version.V_7_6_0)) { - deprecationLogger.deprecatedAndMaybeLog("nGram_tokenizer_deprecation", - "The [nGram] tokenizer name is deprecated and will be removed in a future version. " - + "Please change the tokenizer name to [ngram] instead."); + deprecationLogger.deprecate("nGram_tokenizer_deprecation", + "The [nGram] tokenizer name is deprecated and will be removed in a future version. " + + "Please change the tokenizer name to [ngram] instead."); } return new NGramTokenizer(); })); @@ -563,9 +563,9 @@ public List getPreConfiguredTokenizers() { throw new IllegalArgumentException("The [edgeNGram] tokenizer name was deprecated in 7.6. " + "Please use the tokenizer name to [edge_ngram] for indices created in versions 8 or higher instead."); } else if (version.onOrAfter(org.elasticsearch.Version.V_7_6_0)) { - deprecationLogger.deprecatedAndMaybeLog("edgeNGram_tokenizer_deprecation", - "The [edgeNGram] tokenizer name is deprecated and will be removed in a future version. " - + "Please change the tokenizer name to [edge_ngram] instead."); + deprecationLogger.deprecate("edgeNGram_tokenizer_deprecation", + "The [edgeNGram] tokenizer name is deprecated and will be removed in a future version. " + + "Please change the tokenizer name to [edge_ngram] instead."); } if (version.onOrAfter(Version.V_7_3_0)) { return new EdgeNGramTokenizer(NGramTokenizer.DEFAULT_MIN_NGRAM_SIZE, NGramTokenizer.DEFAULT_MAX_NGRAM_SIZE); diff --git a/modules/analysis-common/src/main/java/org/elasticsearch/analysis/common/SynonymTokenFilterFactory.java b/modules/analysis-common/src/main/java/org/elasticsearch/analysis/common/SynonymTokenFilterFactory.java index 681b2785116fb..721fe7bf91757 100644 --- a/modules/analysis-common/src/main/java/org/elasticsearch/analysis/common/SynonymTokenFilterFactory.java +++ b/modules/analysis-common/src/main/java/org/elasticsearch/analysis/common/SynonymTokenFilterFactory.java @@ -59,10 +59,9 @@ public class SynonymTokenFilterFactory extends AbstractTokenFilterFactory { this.settings = settings; if (settings.get("ignore_case") != null) { - DEPRECATION_LOGGER.deprecatedAndMaybeLog( - "synonym_ignore_case_option", + DEPRECATION_LOGGER.deprecate("synonym_ignore_case_option", "The ignore_case option on the synonym_graph filter is deprecated. " + - "Instead, insert a lowercase filter in the filter chain before the synonym_graph filter."); + "Instead, insert a lowercase filter in the filter chain before the synonym_graph filter."); } this.expand = settings.getAsBoolean("expand", true); diff --git a/modules/ingest-user-agent/src/main/java/org/elasticsearch/ingest/useragent/UserAgentProcessor.java b/modules/ingest-user-agent/src/main/java/org/elasticsearch/ingest/useragent/UserAgentProcessor.java index 57cd6a806908d..91a0563b1ca1f 100644 --- a/modules/ingest-user-agent/src/main/java/org/elasticsearch/ingest/useragent/UserAgentProcessor.java +++ b/modules/ingest-user-agent/src/main/java/org/elasticsearch/ingest/useragent/UserAgentProcessor.java @@ -187,7 +187,7 @@ public UserAgentProcessor create(Map factories, Strin boolean ignoreMissing = readBooleanProperty(TYPE, processorTag, config, "ignore_missing", false); Object ecsValue = config.remove("ecs"); if (ecsValue != null) { - deprecationLogger.deprecatedAndMaybeLog("ingest_useragent_ecs_settings", + deprecationLogger.deprecate("ingest_useragent_ecs_settings", "setting [ecs] is deprecated as ECS format is the default and only option"); } diff --git a/modules/reindex/src/main/java/org/elasticsearch/index/reindex/ReindexValidator.java b/modules/reindex/src/main/java/org/elasticsearch/index/reindex/ReindexValidator.java index ddb1d1fc98788..bd0168fbda42b 100644 --- a/modules/reindex/src/main/java/org/elasticsearch/index/reindex/ReindexValidator.java +++ b/modules/reindex/src/main/java/org/elasticsearch/index/reindex/ReindexValidator.java @@ -67,7 +67,7 @@ void initialValidation(ReindexRequest request) { state); SearchSourceBuilder searchSource = request.getSearchRequest().source(); if (searchSource != null && searchSource.sorts() != null && searchSource.sorts().isEmpty() == false) { - deprecationLogger.deprecatedAndMaybeLog("reindex_sort", SORT_DEPRECATED_MESSAGE); + deprecationLogger.deprecate("reindex_sort", SORT_DEPRECATED_MESSAGE); } } diff --git a/plugins/discovery-azure-classic/src/main/java/org/elasticsearch/plugin/discovery/azure/classic/AzureDiscoveryPlugin.java b/plugins/discovery-azure-classic/src/main/java/org/elasticsearch/plugin/discovery/azure/classic/AzureDiscoveryPlugin.java index af30a0b378ebd..d4d59a52e19bc 100644 --- a/plugins/discovery-azure-classic/src/main/java/org/elasticsearch/plugin/discovery/azure/classic/AzureDiscoveryPlugin.java +++ b/plugins/discovery-azure-classic/src/main/java/org/elasticsearch/plugin/discovery/azure/classic/AzureDiscoveryPlugin.java @@ -48,7 +48,7 @@ public class AzureDiscoveryPlugin extends Plugin implements DiscoveryPlugin { public AzureDiscoveryPlugin(Settings settings) { this.settings = settings; - deprecationLogger.deprecatedAndMaybeLog("azure_discovery_plugin", "azure classic discovery plugin is deprecated."); + deprecationLogger.deprecate("azure_discovery_plugin", "azure classic discovery plugin is deprecated."); logger.trace("starting azure classic discovery plugin..."); } diff --git a/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2ClientSettings.java b/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2ClientSettings.java index 494e564937d07..9127e5040a433 100644 --- a/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2ClientSettings.java +++ b/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2ClientSettings.java @@ -135,13 +135,13 @@ static AWSCredentials loadCredentials(Settings settings) { return null; } else { if (key.length() == 0) { - deprecationLogger.deprecatedAndMaybeLog("ec2_invalid_settings", + deprecationLogger.deprecate("ec2_invalid_settings", "Setting [{}] is set but [{}] is not, which will be unsupported in future", SECRET_KEY_SETTING.getKey(), ACCESS_KEY_SETTING.getKey()); } if (secret.length() == 0) { - deprecationLogger.deprecatedAndMaybeLog("ec2_invalid_settings", - "Setting [{}] is set but [{}] is not, which will be unsupported in future", + deprecationLogger.deprecate("ec2_invalid_settings", + "Setting [{}] is set but [{}] is not, which will be unsupported in future", ACCESS_KEY_SETTING.getKey(), SECRET_KEY_SETTING.getKey()); } diff --git a/qa/evil-tests/src/test/java/org/elasticsearch/common/logging/EvilLoggerTests.java b/qa/evil-tests/src/test/java/org/elasticsearch/common/logging/EvilLoggerTests.java index 5b66f8207d9d6..fd21f6ad03f93 100644 --- a/qa/evil-tests/src/test/java/org/elasticsearch/common/logging/EvilLoggerTests.java +++ b/qa/evil-tests/src/test/java/org/elasticsearch/common/logging/EvilLoggerTests.java @@ -67,6 +67,7 @@ public class EvilLoggerTests extends ESTestCase { @Override public void setUp() throws Exception { + assert "false".equals(System.getProperty("tests.security.manager")) : "-Dtests.security.manager=false has to be set"; super.setUp(); LogConfigurator.registerErrorListener(); } @@ -126,7 +127,7 @@ public void testConcurrentDeprecationLogger() throws IOException, UserException, } for (int j = 0; j < iterations; j++) { for (final Integer id : ids) { - deprecationLogger.deprecatedAndMaybeLog(Integer.toString(id), "This is a maybe logged deprecation message" + id); + deprecationLogger.deprecate(Integer.toString(id), "This is a maybe logged deprecation message" + id); } } @@ -137,12 +138,12 @@ public void testConcurrentDeprecationLogger() throws IOException, UserException, */ final List warnings = threadContext.getResponseHeaders().get("Warning"); final Set actualWarningValues = - warnings.stream().map(s -> DeprecationLogger.extractWarningValueFromWarningHeader(s, true)) + warnings.stream().map(s -> HeaderWarning.extractWarningValueFromWarningHeader(s, true)) .collect(Collectors.toSet()); for (int j = 0; j < 128; j++) { assertThat( actualWarningValues, - hasItem(DeprecationLogger.escapeAndEncode("This is a maybe logged deprecation message" + j))); + hasItem(HeaderWarning.escapeAndEncode("This is a maybe logged deprecation message" + j))); } try { @@ -180,7 +181,7 @@ public void testConcurrentDeprecationLogger() throws IOException, UserException, assertLogLine( deprecationEvents.get(i), Level.WARN, - "org.elasticsearch.common.logging.DeprecationLogger\\$2\\.run", + "org.elasticsearch.common.logging.ThrottlingLogger\\$2\\.run", "This is a maybe logged deprecation message" + i); } @@ -198,17 +199,17 @@ public void testDeprecationLoggerMaybeLog() throws IOException, UserException { final int iterations = randomIntBetween(1, 16); for (int i = 0; i < iterations; i++) { - deprecationLogger.deprecatedAndMaybeLog("key", "This is a maybe logged deprecation message"); + deprecationLogger.deprecate("key", "This is a maybe logged deprecation message"); assertWarnings("This is a maybe logged deprecation message"); } for (int k = 0; k < 128; k++) { for (int i = 0; i < iterations; i++) { - deprecationLogger.deprecatedAndMaybeLog("key" + k, "This is a maybe logged deprecation message" + k); + deprecationLogger.deprecate("key" + k, "This is a maybe logged deprecation message" + k); assertWarnings("This is a maybe logged deprecation message" + k); } } for (int i = 0; i < iterations; i++) { - deprecationLogger.deprecatedAndMaybeLog("key", "This is a maybe logged deprecation message"); + deprecationLogger.deprecate("key", "This is a maybe logged deprecation message"); assertWarnings("This is a maybe logged deprecation message"); } @@ -222,13 +223,13 @@ public void testDeprecationLoggerMaybeLog() throws IOException, UserException { assertLogLine( deprecationEvents.get(0), Level.WARN, - "org.elasticsearch.common.logging.DeprecationLogger\\$2\\.run", + "org.elasticsearch.common.logging.ThrottlingLogger\\$2\\.run", "This is a maybe logged deprecation message"); for (int k = 0; k < 128; k++) { assertLogLine( deprecationEvents.get(1 + k), Level.WARN, - "org.elasticsearch.common.logging.DeprecationLogger\\$2\\.run", + "org.elasticsearch.common.logging.ThrottlingLogger\\$2\\.run", "This is a maybe logged deprecation message" + k); } } @@ -256,7 +257,7 @@ public void testDeprecatedSettings() throws IOException, UserException { assertLogLine( deprecationEvents.get(0), Level.WARN, - "org.elasticsearch.common.logging.DeprecationLogger\\$2\\.run", + "org.elasticsearch.common.logging.ThrottlingLogger\\$2\\.run", "\\[deprecated.foo\\] setting was deprecated in Elasticsearch and will be removed in a future release! " + "See the breaking changes documentation for the next major version."); } 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 5ffee1b4ec417..9461c9026fbeb 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 @@ -343,8 +343,8 @@ public void testDuplicateLogMessages() throws IOException { try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { threadContext.putHeader(Task.X_OPAQUE_ID, "ID1"); DeprecationLogger.setThreadContext(threadContext); - deprecationLogger.deprecatedAndMaybeLog("key", "message1"); - deprecationLogger.deprecatedAndMaybeLog("key", "message2"); + deprecationLogger.deprecate("key", "message1"); + deprecationLogger.deprecate("key", "message2"); assertWarnings("message1", "message2"); final Path path = PathUtils.get(System.getProperty("es.logs.base_path"), @@ -375,8 +375,8 @@ public void testDuplicateLogMessages() throws IOException { try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { threadContext.putHeader(Task.X_OPAQUE_ID, "ID2"); DeprecationLogger.setThreadContext(threadContext); - deprecationLogger.deprecatedAndMaybeLog("key", "message1"); - deprecationLogger.deprecatedAndMaybeLog("key", "message2"); + deprecationLogger.deprecate("key", "message1"); + deprecationLogger.deprecate("key", "message2"); assertWarnings("message1", "message2"); final Path path = PathUtils.get(System.getProperty("es.logs.base_path"), diff --git a/qa/smoke-test-http/src/test/java/org/elasticsearch/http/DeprecationHttpIT.java b/qa/smoke-test-http/src/test/java/org/elasticsearch/http/DeprecationHttpIT.java index c9bed57fb13e7..968a7c0e44434 100644 --- a/qa/smoke-test-http/src/test/java/org/elasticsearch/http/DeprecationHttpIT.java +++ b/qa/smoke-test-http/src/test/java/org/elasticsearch/http/DeprecationHttpIT.java @@ -25,7 +25,7 @@ import org.elasticsearch.client.Request; import org.elasticsearch.client.Response; 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.Setting; import org.elasticsearch.common.settings.Settings; @@ -42,7 +42,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.elasticsearch.common.logging.DeprecationLogger.WARNING_HEADER_PATTERN; import static org.elasticsearch.http.TestDeprecationHeaderRestAction.TEST_DEPRECATED_SETTING_TRUE1; import static org.elasticsearch.http.TestDeprecationHeaderRestAction.TEST_DEPRECATED_SETTING_TRUE2; import static org.elasticsearch.http.TestDeprecationHeaderRestAction.TEST_NOT_DEPRECATED_SETTING; @@ -184,10 +183,10 @@ private void doTestDeprecationWarningsAppearInHeaders() throws IOException { assertThat(deprecatedWarnings, hasSize(headerMatchers.size())); for (final String deprecatedWarning : deprecatedWarnings) { - assertThat(deprecatedWarning, matches(WARNING_HEADER_PATTERN.pattern())); + assertThat(deprecatedWarning, matches(HeaderWarning.WARNING_HEADER_PATTERN.pattern())); } final List actualWarningValues = - deprecatedWarnings.stream().map(s -> DeprecationLogger.extractWarningValueFromWarningHeader(s, true)) + deprecatedWarnings.stream().map(s -> HeaderWarning.extractWarningValueFromWarningHeader(s, true)) .collect(Collectors.toList()); for (Matcher headerMatcher : headerMatchers) { assertThat(actualWarningValues, hasItem(headerMatcher)); diff --git a/qa/smoke-test-http/src/test/java/org/elasticsearch/http/TestDeprecatedQueryBuilder.java b/qa/smoke-test-http/src/test/java/org/elasticsearch/http/TestDeprecatedQueryBuilder.java index 7296874087459..1d2555eb0e636 100644 --- a/qa/smoke-test-http/src/test/java/org/elasticsearch/http/TestDeprecatedQueryBuilder.java +++ b/qa/smoke-test-http/src/test/java/org/elasticsearch/http/TestDeprecatedQueryBuilder.java @@ -80,7 +80,7 @@ public String getWriteableName() { @Override protected Query doToQuery(QueryShardContext context) throws IOException { - deprecationLogger.deprecatedAndMaybeLog(NAME, "[{}] query is deprecated, but used on [{}] index", NAME, context.index().getName()); + deprecationLogger.deprecate(NAME, "[{}] query is deprecated, but used on [{}] index", NAME, context.index().getName()); return Queries.newMatchAllQuery(); } diff --git a/qa/smoke-test-http/src/test/java/org/elasticsearch/http/TestDeprecationHeaderRestAction.java b/qa/smoke-test-http/src/test/java/org/elasticsearch/http/TestDeprecationHeaderRestAction.java index 2b8e35acca9b1..f7cf5481590db 100644 --- a/qa/smoke-test-http/src/test/java/org/elasticsearch/http/TestDeprecationHeaderRestAction.java +++ b/qa/smoke-test-http/src/test/java/org/elasticsearch/http/TestDeprecationHeaderRestAction.java @@ -98,7 +98,7 @@ public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client final Map source = parser.map(); if (source.containsKey("deprecated_settings")) { - deprecationLogger.deprecatedAndMaybeLog("deprecated_settings", DEPRECATED_USAGE); + deprecationLogger.deprecate("deprecated_settings", DEPRECATED_USAGE); settings = (List)source.get("deprecated_settings"); } else { diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataCreateIndexService.java b/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataCreateIndexService.java index 93c245afd438a..85ccc11e504ca 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataCreateIndexService.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataCreateIndexService.java @@ -187,7 +187,7 @@ public void validateDotIndex(String index, ClusterState state, @Nullable Boolean .filter(descriptor -> descriptor.matchesIndexPattern(index)) .collect(toList()); if (matchingDescriptors.isEmpty() && (isHidden == null || isHidden == Boolean.FALSE)) { - deprecationLogger.deprecatedAndMaybeLog("index_name_starts_with_dot", + deprecationLogger.deprecate("index_name_starts_with_dot", "index name [{}] starts with a dot '.', in the next major version, index names " + "starting with a dot are reserved for hidden indices and system indices", index); } else if (matchingDescriptors.size() > 1) { @@ -345,7 +345,7 @@ public ClusterState applyCreateIndexRequest(ClusterState currentState, CreateInd request.index(), isHiddenFromRequest); if (v1Templates.size() > 1) { - deprecationLogger.deprecatedAndMaybeLog("index_template_multiple_match", + deprecationLogger.deprecate("index_template_multiple_match", "index [{}] matches multiple legacy templates [{}], composable templates will only match a single template", request.index(), v1Templates.stream().map(IndexTemplateMetadata::name).sorted().collect(Collectors.joining(", "))); } @@ -1269,7 +1269,7 @@ public static void validateTranslogRetentionSettings(Settings indexSettings) { if (IndexSettings.INDEX_SOFT_DELETES_SETTING.get(indexSettings) && (IndexSettings.INDEX_TRANSLOG_RETENTION_AGE_SETTING.exists(indexSettings) || IndexSettings.INDEX_TRANSLOG_RETENTION_SIZE_SETTING.exists(indexSettings))) { - deprecationLogger.deprecatedAndMaybeLog("translog_retention", "Translog retention settings [index.translog.retention.age] " + deprecationLogger.deprecate("translog_retention", "Translog retention settings [index.translog.retention.age] " + "and [index.translog.retention.size] are deprecated and effectively ignored. They will be removed in a future version."); } } 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 835219b54345c..caa15eb560830 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateService.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateService.java @@ -40,7 +40,7 @@ import org.elasticsearch.common.ValidationException; import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.logging.DeprecationLogger; +import org.elasticsearch.common.logging.HeaderWarning; import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.settings.IndexScopedSettings; import org.elasticsearch.common.settings.Settings; @@ -79,8 +79,6 @@ public class MetadataIndexTemplateService { private static final Logger logger = LogManager.getLogger(MetadataIndexTemplateService.class); - private static final DeprecationLogger deprecationLogger = new DeprecationLogger(logger); - private final ClusterService clusterService; private final AliasValidator aliasValidator; private final IndicesService indicesService; @@ -407,7 +405,7 @@ public ClusterState addIndexTemplateV2(final ClusterState currentState, final bo .collect(Collectors.joining(",")), name); logger.warn(warning); - deprecationLogger.deprecatedAndMaybeLog("index_template_pattern_overlap", warning); + HeaderWarning.addWarning(warning); } ComposableIndexTemplate finalIndexTemplate = template; @@ -642,7 +640,7 @@ static ClusterState innerPutTemplate(final ClusterState currentState, PutRequest .collect(Collectors.joining(",")), request.name); logger.warn(warning); - deprecationLogger.deprecatedAndMaybeLog("index_template_pattern_overlap", warning); + HeaderWarning.addWarning(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/joda/Joda.java b/server/src/main/java/org/elasticsearch/common/joda/Joda.java index 45587f6bb3df9..4eda6fe333a60 100644 --- a/server/src/main/java/org/elasticsearch/common/joda/Joda.java +++ b/server/src/main/java/org/elasticsearch/common/joda/Joda.java @@ -269,15 +269,15 @@ public static JodaDateFormatter forPattern(String input) { private static void maybeLogJodaDeprecation(String input) { if (input.contains("CC")) { - deprecationLogger.deprecatedAndMaybeLog("joda-century-of-era-format", + deprecationLogger.deprecate("joda-century-of-era-format", "Use of 'C' (century-of-era) is deprecated and will not be supported in the next major version of Elasticsearch."); } if (input.contains("YY")) { - deprecationLogger.deprecatedAndMaybeLog("joda-year-of-era-format", "Use of 'Y' (year-of-era) will change to 'y' in the" + - " next major version of Elasticsearch. Prefix your date format with '8' to use the new specifier."); + deprecationLogger.deprecate("joda-year-of-era-format", "Use of 'Y' (year-of-era) will change to 'y' in the" + + " next major version of Elasticsearch. Prefix your date format with '8' to use the new specifier."); } if (input.contains("xx")) { - deprecationLogger.deprecatedAndMaybeLog("joda-week-based-year-format","Use of 'x' (week-based-year) will change" + + deprecationLogger.deprecate("joda-week-based-year-format", "Use of 'x' (week-based-year) will change" + " to 'Y' in the next major version of Elasticsearch. Prefix your date format with '8' to use the new specifier."); } } @@ -375,11 +375,11 @@ public int parseInto(DateTimeParserBucket bucket, String text, int position) { long millis = new BigDecimal(text).longValue() * factor; // check for deprecations, but after it has parsed correctly so invalid values aren't counted as deprecated if (millis < 0) { - deprecationLogger.deprecatedAndMaybeLog("epoch-negative", "Use of negative values" + + deprecationLogger.deprecate("epoch-negative", "Use of negative values" + " in epoch time formats is deprecated and will not be supported in the next major version of Elasticsearch."); } if (scientificNotation.matcher(text).find()) { - deprecationLogger.deprecatedAndMaybeLog("epoch-scientific-notation", "Use of scientific notation" + + deprecationLogger.deprecate("epoch-scientific-notation", "Use of scientific notation" + " in epoch time formats is deprecated and will not be supported in the next major version of Elasticsearch."); } DateTime dt = new DateTime(millis, DateTimeZone.UTC); diff --git a/server/src/main/java/org/elasticsearch/common/logging/DeprecatedMessage.java b/server/src/main/java/org/elasticsearch/common/logging/DeprecatedMessage.java index e0ea1f74f92e4..2cc882d61695a 100644 --- a/server/src/main/java/org/elasticsearch/common/logging/DeprecatedMessage.java +++ b/server/src/main/java/org/elasticsearch/common/logging/DeprecatedMessage.java @@ -43,7 +43,7 @@ public String toString() { } }; - return new ESLogMessage() + return new ESLogMessage(messagePattern, args) .field("message", value) .field(X_OPAQUE_ID_FIELD_NAME, xOpaqueId); } diff --git a/server/src/main/java/org/elasticsearch/common/logging/DeprecationLogger.java b/server/src/main/java/org/elasticsearch/common/logging/DeprecationLogger.java index 080e2f03929c0..b7716a9b91a8d 100644 --- a/server/src/main/java/org/elasticsearch/common/logging/DeprecationLogger.java +++ b/server/src/main/java/org/elasticsearch/common/logging/DeprecationLogger.java @@ -21,79 +21,23 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.elasticsearch.Build; -import org.elasticsearch.Version; -import org.elasticsearch.common.SuppressLoggerChecks; import org.elasticsearch.common.util.concurrent.ThreadContext; -import org.elasticsearch.tasks.Task; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.BitSet; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** - * A logger that logs deprecation notices. + * A logger that logs deprecation notices. Logger should be initialized with a parent logger which name will be used + * for deprecation logger. For instance new DeprecationLogger("org.elasticsearch.test.SomeClass") will + * result in a deprecation logger with name org.elasticsearch.deprecation.test.SomeClass. This allows to use + * deprecation logger defined in log4j2.properties. + * + * Deprecation logs are written to deprecation log file - defined in log4j2.properties, as well as warnings added to a response header. + * All deprecation usages are throttled basing on a key. Key is a string provided in an argument and can be prefixed with + * X-Opaque-Id. This allows to throttle deprecations per client usage. + * deprecationLogger.deprecate("key","message {}", "param"); + * + * @see ThrottlingAndHeaderWarningLogger for throttling and header warnings implementation details */ public class DeprecationLogger { - - private final Logger logger; - - /** - * This is set once by the {@code Node} constructor, but it uses {@link CopyOnWriteArraySet} to ensure that tests can run in parallel. - *

- * Integration tests will create separate nodes within the same classloader, thus leading to a shared, {@code static} state. - * In order for all tests to appropriately be handled, this must be able to remember all {@link ThreadContext}s that it is - * given in a thread safe manner. - *

- * For actual usage, multiple nodes do not share the same JVM and therefore this will only be set once in practice. - */ - private static final CopyOnWriteArraySet THREAD_CONTEXT = new CopyOnWriteArraySet<>(); - - /** - * Set the {@link ThreadContext} used to add deprecation headers to network responses. - *

- * This is expected to only be invoked by the {@code Node}'s constructor (therefore once outside of tests). - * - * @param threadContext The thread context owned by the {@code ThreadPool} (and implicitly a {@code Node}) - * @throws IllegalStateException if this {@code threadContext} has already been set - */ - public static void setThreadContext(ThreadContext threadContext) { - Objects.requireNonNull(threadContext, "Cannot register a null ThreadContext"); - - // add returning false means it _did_ have it already - if (THREAD_CONTEXT.add(threadContext) == false) { - throw new IllegalStateException("Double-setting ThreadContext not allowed!"); - } - } - - /** - * Remove the {@link ThreadContext} used to add deprecation headers to network responses. - *

- * This is expected to only be invoked by the {@code Node}'s {@code close} method (therefore once outside of tests). - * - * @param threadContext The thread context owned by the {@code ThreadPool} (and implicitly a {@code Node}) - * @throws IllegalStateException if this {@code threadContext} is unknown (and presumably already unset before) - */ - public static void removeThreadContext(ThreadContext threadContext) { - assert threadContext != null; - - // remove returning false means it did not have it already - if (THREAD_CONTEXT.remove(threadContext) == false) { - throw new IllegalStateException("Removing unknown ThreadContext not allowed!"); - } - } + private final ThrottlingAndHeaderWarningLogger deprecationLogger; /** * Creates a new deprecation logger based on the parent logger. Automatically @@ -102,316 +46,45 @@ public static void removeThreadContext(ThreadContext threadContext) { * the "org.elasticsearch" namespace. */ public DeprecationLogger(Logger parentLogger) { + deprecationLogger = new ThrottlingAndHeaderWarningLogger(deprecatedLoggerName(parentLogger)); + } + + private static Logger deprecatedLoggerName(Logger parentLogger) { String name = parentLogger.getName(); if (name.startsWith("org.elasticsearch")) { name = name.replace("org.elasticsearch.", "org.elasticsearch.deprecation."); } else { name = "deprecation." + name; } - this.logger = LogManager.getLogger(name); - } - - // LRU set of keys used to determine if a deprecation message should be emitted to the deprecation logs - private final Set keys = Collections.newSetFromMap(Collections.synchronizedMap(new LinkedHashMap<>() { - @Override - protected boolean removeEldestEntry(final Map.Entry eldest) { - return size() > 128; - } - })); - - /** - * Adds a formatted warning message as a response header on the thread context, and logs a deprecation message if the associated key has - * not recently been seen. - * - * @param key the key used to determine if this deprecation should be logged - * @param msg the message to log - * @param params parameters to the message - */ - public void deprecatedAndMaybeLog(final String key, final String msg, final Object... params) { - String xOpaqueId = getXOpaqueId(THREAD_CONTEXT); - boolean shouldLog = keys.add(xOpaqueId + key); - deprecated(THREAD_CONTEXT, msg, shouldLog, params); - } - - /* - * 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. - */ - private static final String WARNING_PREFIX = - String.format( - Locale.ROOT, - "299 Elasticsearch-%s%s-%s", - Version.CURRENT.toString(), - Build.CURRENT.isSnapshot() ? "-SNAPSHOT" : "", - Build.CURRENT.hash()); - - /** - * 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. - */ - public static final Pattern WARNING_HEADER_PATTERN = Pattern.compile( - "299 " + // warn 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 - "\"((?:\t| |!|[\\x23-\\x5B]|[\\x5D-\\x7E]|[\\x80-\\xFF]|\\\\|\\\\\")*)\"( " + // quoted warning value, captured - // quoted RFC 1123 date format - "\"" + // opening quote - "(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), " + // weekday - "\\d{2} " + // 2-digit day - "(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) " + // month - "\\d{4} " + // 4-digit year - "\\d{2}:\\d{2}:\\d{2} " + // (two-digit hour):(two-digit minute):(two-digit second) - "GMT" + // GMT - "\")?"); // closing quote (optional, since an older version can still send a warn-date) - - public static final Pattern WARNING_XCONTENT_LOCATION_PATTERN = Pattern.compile("^\\[.*?]\\[-?\\d+:-?\\d+] "); - - /** - * Extracts the warning value from the value of a warning header that is formatted according to RFC 7234. That is, given a string - * {@code 299 Elasticsearch-6.0.0 "warning value"}, the return value of this method would be {@code warning value}. - * - * @param s the value of a warning header formatted according to RFC 7234. - * @return the extracted warning value - */ - public static String extractWarningValueFromWarningHeader(final String s, boolean stripXContentPosition) { - /* - * We know the exact format of the warning header, so to extract the warning value we can skip forward from the front to the first - * quote and we know the last quote is at the end of the string - * - * 299 Elasticsearch-6.0.0 "warning value" - * ^ ^ - * firstQuote lastQuote - * - * We parse this manually rather than using the capturing regular expression because the regular expression involves a lot of - * backtracking and carries a performance penalty. However, when assertions are enabled, we still use the regular expression to - * verify that we are maintaining the warning header format. - */ - final int firstQuote = s.indexOf('\"'); - final int lastQuote = s.length() - 1; - String warningValue = s.substring(firstQuote + 1, lastQuote); - assert assertWarningValue(s, warningValue); - if (stripXContentPosition) { - Matcher matcher = WARNING_XCONTENT_LOCATION_PATTERN.matcher(warningValue); - if (matcher.find()) { - warningValue = warningValue.substring(matcher.end()); - } - } - return warningValue; - } - - /** - * Assert that the specified string has the warning value equal to the provided warning value. - * - * @param s the string representing a full warning header - * @param warningValue the expected warning header - * @return {@code true} if the specified string has the expected warning value - */ - private static boolean assertWarningValue(final String s, final String warningValue) { - final Matcher matcher = WARNING_HEADER_PATTERN.matcher(s); - final boolean matches = matcher.matches(); - assert matches; - return matcher.group(1).equals(warningValue); - } - - /** - * Logs a deprecated message to the deprecation log, as well as to the local {@link ThreadContext}. - * - * @param threadContexts The node's {@link ThreadContext} (outside of concurrent tests, this should only ever have one context). - * @param message The deprecation message. - * @param params The parameters used to fill in the message, if any exist. - */ - void deprecated(final Set threadContexts, final String message, final Object... params) { - deprecated(threadContexts, message, true, params); - } - - void deprecated(final Set threadContexts, final String message, final boolean shouldLog, final Object... params) { - final Iterator iterator = threadContexts.iterator(); - if (iterator.hasNext()) { - final String formattedMessage = LoggerMessageFormat.format(message, params); - final String warningHeaderValue = formatWarning(formattedMessage); - assert WARNING_HEADER_PATTERN.matcher(warningHeaderValue).matches(); - assert extractWarningValueFromWarningHeader(warningHeaderValue, false).equals(escapeAndEncode(formattedMessage)); - while (iterator.hasNext()) { - try { - final ThreadContext next = iterator.next(); - next.addResponseHeader("Warning", warningHeaderValue); - } catch (final IllegalStateException e) { - // ignored; it should be removed shortly - } - } - } - - if (shouldLog) { - AccessController.doPrivileged(new PrivilegedAction() { - @SuppressLoggerChecks(reason = "safely delegates to logger") - @Override - public Void run() { - /* - * There should be only one threadContext (in prod env), @see DeprecationLogger#setThreadContext - */ - String opaqueId = getXOpaqueId(threadContexts); - - logger.warn(DeprecatedMessage.of(opaqueId, message, params)); - return null; - } - }); - } - } - - public String getXOpaqueId(Set threadContexts) { - return threadContexts.stream() - .filter(t -> t.getHeader(Task.X_OPAQUE_ID) != null) - .findFirst() - .map(t -> t.getHeader(Task.X_OPAQUE_ID)) - .orElse(""); + return LogManager.getLogger(name); } - /** - * 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 s the warning string to format - * @return a warning value formatted according to RFC 7234 - */ - public static String formatWarning(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; - final StringBuilder sb = new StringBuilder(length); - sb.append(WARNING_PREFIX).append(" \"").append(escapeAndEncode(s)).append("\""); - return sb.toString(); + public static void setThreadContext(ThreadContext threadContext) { + HeaderWarning.setThreadContext(threadContext); } - /** - * Escape and encode a string as a valid RFC 7230 quoted-string. - * - * @param s the string to escape and encode - * @return the escaped and encoded string - */ - public static String escapeAndEncode(final String s) { - return encode(escapeBackslashesAndQuotes(s)); + public static void removeThreadContext(ThreadContext threadContext) { + HeaderWarning.removeThreadContext(threadContext); } /** - * Escape backslashes and quotes in the specified string. - * - * @param s the string to escape - * @return the escaped string + * Logs a deprecation message, adding a formatted warning message as a response header on the thread context. + * The deprecation message will be throttled to deprecation log. + * method returns a builder as more methods are expected to be chained. */ - static String escapeBackslashesAndQuotes(final String s) { - /* - * We want a fast path check to avoid creating the string builder and copying characters if needed. So we walk the string looking - * for either of the characters that we need to escape. If we find a character that needs escaping, we start over and - */ - boolean escapingNeeded = false; - for (int i = 0; i < s.length(); i++) { - final char c = s.charAt(i); - if (c == '\\' || c == '"') { - escapingNeeded = true; - break; - } - } - - if (escapingNeeded) { - final StringBuilder sb = new StringBuilder(); - for (final char c : s.toCharArray()) { - if (c == '\\' || c == '"') { - sb.append("\\"); - } - sb.append(c); - } - return sb.toString(); - } else { - return s; - } + public DeprecationLoggerBuilder deprecate(final String key, final String msg, final Object... params) { + return new DeprecationLoggerBuilder() + .withDeprecation(key, msg, params); } - private static BitSet doesNotNeedEncoding; + public class DeprecationLoggerBuilder { - static { - doesNotNeedEncoding = new BitSet(1 + 0xFF); - doesNotNeedEncoding.set('\t'); - doesNotNeedEncoding.set(' '); - doesNotNeedEncoding.set('!'); - doesNotNeedEncoding.set('\\'); - doesNotNeedEncoding.set('"'); - // we have to skip '%' which is 0x25 so that it is percent-encoded too - for (int i = 0x23; i <= 0x24; i++) { - doesNotNeedEncoding.set(i); - } - for (int i = 0x26; i <= 0x5B; i++) { - doesNotNeedEncoding.set(i); - } - for (int i = 0x5D; i <= 0x7E; i++) { - doesNotNeedEncoding.set(i); - } - for (int i = 0x80; i <= 0xFF; i++) { - doesNotNeedEncoding.set(i); + public DeprecationLoggerBuilder withDeprecation(String key, String msg, Object[] params) { + String opaqueId = HeaderWarning.getXOpaqueId(); + ESLogMessage deprecationMessage = DeprecatedMessage.of(opaqueId, msg, params); + deprecationLogger.throttleLogAndAddWarning(key, deprecationMessage); + return this; } - assert doesNotNeedEncoding.get('%') == false : doesNotNeedEncoding; - } - - private static final Charset UTF_8 = StandardCharsets.UTF_8; - /** - * Encode a string containing characters outside of the legal characters for an RFC 7230 quoted-string. - * - * @param s the string to encode - * @return the encoded string - */ - static String encode(final String s) { - // first check if the string needs any encoding; this is the fast path and we want to avoid creating a string builder and copying - boolean encodingNeeded = false; - for (int i = 0; i < s.length(); i++) { - int current = s.charAt(i); - if (doesNotNeedEncoding.get(current) == false) { - encodingNeeded = true; - break; - } - } - - if (encodingNeeded == false) { - return s; - } - - final StringBuilder sb = new StringBuilder(s.length()); - for (int i = 0; i < s.length();) { - int current = s.charAt(i); - /* - * Either the character does not need encoding or it does; when the character does not need encoding we append the character to - * a buffer and move to the next character and when the character does need encoding, we peel off as many characters as possible - * which we encode using UTF-8 until we encounter another character that does not need encoding. - */ - if (doesNotNeedEncoding.get(current)) { - // append directly and move to the next character - sb.append((char) current); - i++; - } else { - int startIndex = i; - do { - i++; - } while (i < s.length() && doesNotNeedEncoding.get(s.charAt(i)) == false); - - final byte[] bytes = s.substring(startIndex, i).getBytes(UTF_8); - // noinspection ForLoopReplaceableByForEach - for (int j = 0; j < bytes.length; j++) { - sb.append('%').append(hex(bytes[j] >> 4)).append(hex(bytes[j])); - } - } - } - return sb.toString(); } - - private static char hex(int b) { - final char ch = Character.forDigit(b & 0xF, 16); - if (Character.isLetter(ch)) { - return Character.toUpperCase(ch); - } else { - return ch; - } - } - } diff --git a/server/src/main/java/org/elasticsearch/common/logging/ESLogMessage.java b/server/src/main/java/org/elasticsearch/common/logging/ESLogMessage.java index 47e05fe44f8c7..590743e8fe622 100644 --- a/server/src/main/java/org/elasticsearch/common/logging/ESLogMessage.java +++ b/server/src/main/java/org/elasticsearch/common/logging/ESLogMessage.java @@ -36,10 +36,13 @@ */ public class ESLogMessage extends MapMessage { private final List arguments = new ArrayList<>(); + private String messagePattern; public ESLogMessage(String messagePattern, Object... args) { super(new LinkedHashMap<>()); Collections.addAll(this.arguments, args); + this.messagePattern = messagePattern; + Object message = new Object() { @Override public String toString() { @@ -108,4 +111,12 @@ public static String asJsonArray(Stream stream) { .map(ESLogMessage::inQuotes) .collect(Collectors.joining(", ")) + "]"; } + + public Object[] getArguments() { + return arguments.toArray(); + } + + public String getMessagePattern() { + return messagePattern; + } } diff --git a/server/src/main/java/org/elasticsearch/common/logging/HeaderWarning.java b/server/src/main/java/org/elasticsearch/common/logging/HeaderWarning.java new file mode 100644 index 0000000000000..714c738a50e57 --- /dev/null +++ b/server/src/main/java/org/elasticsearch/common/logging/HeaderWarning.java @@ -0,0 +1,347 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.common.logging; + +import org.elasticsearch.Build; +import org.elasticsearch.Version; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.tasks.Task; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.BitSet; +import java.util.Iterator; +import java.util.Locale; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * This is a simplistic logger that adds warning messages to HTTP headers. + * Use HeaderWarning.addWarning(message,params). Message will be formatted according to RFC7234. + * The result will be returned as HTTP response headers. + */ +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. + */ + public static final Pattern WARNING_HEADER_PATTERN = Pattern.compile( + "299 " + // warn 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 + "\"((?:\t| |!|[\\x23-\\x5B]|[\\x5D-\\x7E]|[\\x80-\\xFF]|\\\\|\\\\\")*)\"( " + // quoted warning value, captured + // quoted RFC 1123 date format + "\"" + // opening quote + "(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), " + // weekday + "\\d{2} " + // 2-digit day + "(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) " + // month + "\\d{4} " + // 4-digit year + "\\d{2}:\\d{2}:\\d{2} " + // (two-digit hour):(two-digit minute):(two-digit second) + "GMT" + // GMT + "\")?"); // closing quote (optional, since an older version can still send a warn-date) + public static final Pattern WARNING_XCONTENT_LOCATION_PATTERN = Pattern.compile("^\\[.*?]\\[-?\\d+:-?\\d+] "); + + /* + * 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. + */ + private static final String WARNING_PREFIX = + String.format( + Locale.ROOT, + "299 Elasticsearch-%s%s-%s", + Version.CURRENT.toString(), + Build.CURRENT.isSnapshot() ? "-SNAPSHOT" : "", + Build.CURRENT.hash()); + + private static BitSet doesNotNeedEncoding; + + static { + doesNotNeedEncoding = new BitSet(1 + 0xFF); + doesNotNeedEncoding.set('\t'); + doesNotNeedEncoding.set(' '); + doesNotNeedEncoding.set('!'); + doesNotNeedEncoding.set('\\'); + doesNotNeedEncoding.set('"'); + // we have to skip '%' which is 0x25 so that it is percent-encoded too + for (int i = 0x23; i <= 0x24; i++) { + doesNotNeedEncoding.set(i); + } + for (int i = 0x26; i <= 0x5B; i++) { + doesNotNeedEncoding.set(i); + } + for (int i = 0x5D; i <= 0x7E; i++) { + doesNotNeedEncoding.set(i); + } + for (int i = 0x80; i <= 0xFF; i++) { + doesNotNeedEncoding.set(i); + } + assert doesNotNeedEncoding.get('%') == false : doesNotNeedEncoding; + } + + private static final Charset UTF_8 = StandardCharsets.UTF_8; + + /** + * This is set once by the {@code Node} constructor, but it uses {@link CopyOnWriteArraySet} to ensure that tests can run in parallel. + *

+ * Integration tests will create separate nodes within the same classloader, thus leading to a shared, {@code static} state. + * In order for all tests to appropriately be handled, this must be able to remember all {@link ThreadContext}s that it is + * given in a thread safe manner. + *

+ * For actual usage, multiple nodes do not share the same JVM and therefore this will only be set once in practice. + */ + static final CopyOnWriteArraySet THREAD_CONTEXT = new CopyOnWriteArraySet<>(); + + /** + * Set the {@link ThreadContext} used to add warning headers to network responses. + *

+ * This is expected to only be invoked by the {@code Node}'s constructor (therefore once outside of tests). + * + * @param threadContext The thread context owned by the {@code ThreadPool} (and implicitly a {@code Node}) + * @throws IllegalStateException if this {@code threadContext} has already been set + */ + public static void setThreadContext(ThreadContext threadContext) { + Objects.requireNonNull(threadContext, "Cannot register a null ThreadContext"); + + // add returning false means it _did_ have it already + if (THREAD_CONTEXT.add(threadContext) == false) { + throw new IllegalStateException("Double-setting ThreadContext not allowed!"); + } + } + + /** + * Remove the {@link ThreadContext} used to add warning headers to network responses. + *

+ * This is expected to only be invoked by the {@code Node}'s {@code close} method (therefore once outside of tests). + * + * @param threadContext The thread context owned by the {@code ThreadPool} (and implicitly a {@code Node}) + * @throws IllegalStateException if this {@code threadContext} is unknown (and presumably already unset before) + */ + public static void removeThreadContext(ThreadContext threadContext) { + assert threadContext != null; + + // remove returning false means it did not have it already + if (THREAD_CONTEXT.remove(threadContext) == false) { + throw new IllegalStateException("Removing unknown ThreadContext not allowed!"); + } + } + + /** + * Extracts the warning value from the value of a warning header that is formatted according to RFC 7234. That is, given a string + * {@code 299 Elasticsearch-6.0.0 "warning value"}, the return value of this method would be {@code warning value}. + * + * @param s the value of a warning header formatted according to RFC 7234. + * @return the extracted warning value + */ + public static String extractWarningValueFromWarningHeader(final String s, boolean stripXContentPosition) { + /* + * We know the exact format of the warning header, so to extract the warning value we can skip forward from the front to the first + * quote and we know the last quote is at the end of the string + * + * 299 Elasticsearch-6.0.0 "warning value" + * ^ ^ + * firstQuote lastQuote + * + * We parse this manually rather than using the capturing regular expression because the regular expression involves a lot of + * backtracking and carries a performance penalty. However, when assertions are enabled, we still use the regular expression to + * verify that we are maintaining the warning header format. + */ + final int firstQuote = s.indexOf('\"'); + final int lastQuote = s.length() - 1; + String warningValue = s.substring(firstQuote + 1, lastQuote); + assert assertWarningValue(s, warningValue); + if (stripXContentPosition) { + Matcher matcher = WARNING_XCONTENT_LOCATION_PATTERN.matcher(warningValue); + if (matcher.find()) { + warningValue = warningValue.substring(matcher.end()); + } + } + return warningValue; + } + + /** + * Assert that the specified string has the warning value equal to the provided warning value. + * + * @param s the string representing a full warning header + * @param warningValue the expected warning header + * @return {@code true} if the specified string has the expected warning value + */ + private static boolean assertWarningValue(final String s, final String warningValue) { + final Matcher matcher = WARNING_HEADER_PATTERN.matcher(s); + final boolean matches = matcher.matches(); + assert matches; + return matcher.group(1).equals(warningValue); + } + + /** + * 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 s the warning string to format + * @return a warning value formatted according to RFC 7234 + */ + public static String formatWarning(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; + final StringBuilder sb = new StringBuilder(length); + sb.append(WARNING_PREFIX).append(" \"").append(escapeAndEncode(s)).append("\""); + return sb.toString(); + } + + /** + * Escape and encode a string as a valid RFC 7230 quoted-string. + * + * @param s the string to escape and encode + * @return the escaped and encoded string + */ + public static String escapeAndEncode(final String s) { + return encode(escapeBackslashesAndQuotes(s)); + } + + /** + * Escape backslashes and quotes in the specified string. + * + * @param s the string to escape + * @return the escaped string + */ + static String escapeBackslashesAndQuotes(final String s) { + /* + * We want a fast path check to avoid creating the string builder and copying characters if needed. So we walk the string looking + * for either of the characters that we need to escape. If we find a character that needs escaping, we start over and + */ + boolean escapingNeeded = false; + for (int i = 0; i < s.length(); i++) { + final char c = s.charAt(i); + if (c == '\\' || c == '"') { + escapingNeeded = true; + break; + } + } + + if (escapingNeeded) { + final StringBuilder sb = new StringBuilder(); + for (final char c : s.toCharArray()) { + if (c == '\\' || c == '"') { + sb.append("\\"); + } + sb.append(c); + } + return sb.toString(); + } else { + return s; + } + } + + /** + * Encode a string containing characters outside of the legal characters for an RFC 7230 quoted-string. + * + * @param s the string to encode + * @return the encoded string + */ + static String encode(final String s) { + // first check if the string needs any encoding; this is the fast path and we want to avoid creating a string builder and copying + boolean encodingNeeded = false; + for (int i = 0; i < s.length(); i++) { + int current = s.charAt(i); + if (doesNotNeedEncoding.get(current) == false) { + encodingNeeded = true; + break; + } + } + + if (encodingNeeded == false) { + return s; + } + + final StringBuilder sb = new StringBuilder(s.length()); + for (int i = 0; i < s.length(); ) { + int current = s.charAt(i); + /* + * Either the character does not need encoding or it does; when the character does not need encoding we append the character to + * a buffer and move to the next character and when the character does need encoding, we peel off as many characters as possible + * which we encode using UTF-8 until we encounter another character that does not need encoding. + */ + if (doesNotNeedEncoding.get(current)) { + // append directly and move to the next character + sb.append((char) current); + i++; + } else { + int startIndex = i; + do { + i++; + } while (i < s.length() && doesNotNeedEncoding.get(s.charAt(i)) == false); + + final byte[] bytes = s.substring(startIndex, i).getBytes(UTF_8); + // noinspection ForLoopReplaceableByForEach + for (int j = 0; j < bytes.length; j++) { + sb.append('%').append(hex(bytes[j] >> 4)).append(hex(bytes[j])); + } + } + } + return sb.toString(); + } + + private static char hex(int b) { + final char ch = Character.forDigit(b & 0xF, 16); + if (Character.isLetter(ch)) { + return Character.toUpperCase(ch); + } else { + return ch; + } + } + + public static String getXOpaqueId() { + return THREAD_CONTEXT.stream() + .filter(t -> t.getHeader(Task.X_OPAQUE_ID) != null) + .findFirst() + .map(t -> t.getHeader(Task.X_OPAQUE_ID)) + .orElse(""); + } + + public static void addWarning(String message, Object... params) { + addWarning(THREAD_CONTEXT, message, params); + } + + // package scope for testing + static void addWarning(Set threadContexts, String message, Object... params) { + final Iterator iterator = threadContexts.iterator(); + if (iterator.hasNext()) { + final String formattedMessage = LoggerMessageFormat.format(message, params); + final String warningHeaderValue = formatWarning(formattedMessage); + assert WARNING_HEADER_PATTERN.matcher(warningHeaderValue).matches(); + assert extractWarningValueFromWarningHeader(warningHeaderValue, false) + .equals(escapeAndEncode(formattedMessage)); + while (iterator.hasNext()) { + try { + final ThreadContext next = iterator.next(); + next.addResponseHeader("Warning", warningHeaderValue); + } catch (final IllegalStateException e) { + // ignored; it should be removed shortly + } + } + } + } +} diff --git a/server/src/main/java/org/elasticsearch/common/logging/ThrottlingAndHeaderWarningLogger.java b/server/src/main/java/org/elasticsearch/common/logging/ThrottlingAndHeaderWarningLogger.java new file mode 100644 index 0000000000000..0dec2b45d0244 --- /dev/null +++ b/server/src/main/java/org/elasticsearch/common/logging/ThrottlingAndHeaderWarningLogger.java @@ -0,0 +1,49 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.common.logging; + +import org.apache.logging.log4j.Logger; + +/** + * This class wraps both HeaderWarningLogger and ThrottlingLogger + * which is a common use case across Elasticsearch + */ +class ThrottlingAndHeaderWarningLogger { + private final ThrottlingLogger throttlingLogger; + + ThrottlingAndHeaderWarningLogger(Logger logger) { + this.throttlingLogger = new ThrottlingLogger(logger); + } + + /** + * Adds a formatted warning message as a response header on the thread context, and logs a message if the associated key has + * not recently been seen. + * + * @param key the key used to determine if this message should be logged + * @param message the message to log + */ + void throttleLogAndAddWarning(final String key, ESLogMessage message) { + String messagePattern = message.getMessagePattern(); + Object[] arguments = message.getArguments(); + HeaderWarning.addWarning(messagePattern, arguments); + throttlingLogger.throttleLog(key, message); + } + +} diff --git a/server/src/main/java/org/elasticsearch/common/logging/ThrottlingLogger.java b/server/src/main/java/org/elasticsearch/common/logging/ThrottlingLogger.java new file mode 100644 index 0000000000000..072f7c5c05a0c --- /dev/null +++ b/server/src/main/java/org/elasticsearch/common/logging/ThrottlingLogger.java @@ -0,0 +1,79 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.common.logging; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.message.Message; +import org.elasticsearch.common.SuppressLoggerChecks; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +/** + * TODO wrapping logging this way limits the usage of %location. It will think this is used from that class. + *

+ * This is a wrapper around a logger that allows to throttle log messages. + * In order to throttle a key has to be used and throttling happens per each key combined with X-Opaque-Id. + * X-Opaque-Id allows throttling per user. This value is set in ThreadContext from X-Opaque-Id HTTP header. + *

+ * The throttling algorithm is relying on LRU set of keys which evicts entries when its size is > 128. + * When a log with a key is emitted, it won't be logged again until the set reaches size 128 and the key is removed from the set. + * + * @see HeaderWarning + */ +class ThrottlingLogger { + + // LRU set of keys used to determine if a message should be emitted to the logs + private final Set keys = Collections.newSetFromMap(Collections.synchronizedMap(new LinkedHashMap() { + @Override + protected boolean removeEldestEntry(final Map.Entry eldest) { + return size() > 128; + } + })); + + private final Logger logger; + + ThrottlingLogger(Logger logger) { + this.logger = logger; + } + + void throttleLog(String key, Message message) { + String xOpaqueId = HeaderWarning.getXOpaqueId(); + boolean shouldLog = keys.add(xOpaqueId + key); + if (shouldLog) { + log(message); + } + } + + private void log(Message message) { + AccessController.doPrivileged(new PrivilegedAction() { + @SuppressLoggerChecks(reason = "safely delegates to logger") + @Override + public Void run() { + logger.warn(message); + return null; + } + }); + } +} 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 614a72f3a0d90..bba96575fe79f 100644 --- a/server/src/main/java/org/elasticsearch/common/settings/Setting.java +++ b/server/src/main/java/org/elasticsearch/common/settings/Setting.java @@ -522,11 +522,9 @@ 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(); - Settings.DeprecationLoggerHolder.deprecationLogger.deprecatedAndMaybeLog( - 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); + Settings.DeprecationLoggerHolder.deprecationLogger + .deprecate(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); } } diff --git a/server/src/main/java/org/elasticsearch/common/time/DateUtils.java b/server/src/main/java/org/elasticsearch/common/time/DateUtils.java index e3d6270da9e01..bb4b99dd5cf4d 100644 --- a/server/src/main/java/org/elasticsearch/common/time/DateUtils.java +++ b/server/src/main/java/org/elasticsearch/common/time/DateUtils.java @@ -198,7 +198,7 @@ public static ZoneId dateTimeZoneToZoneId(DateTimeZone timeZone) { public static ZoneId of(String zoneId) { String deprecatedId = DEPRECATED_SHORT_TIMEZONES.get(zoneId); if (deprecatedId != null) { - deprecationLogger.deprecatedAndMaybeLog("timezone", + deprecationLogger.deprecate("timezone", "Use of short timezone id " + zoneId + " is deprecated. Use " + deprecatedId + " instead"); return ZoneId.of(deprecatedId); } diff --git a/server/src/main/java/org/elasticsearch/common/unit/ByteSizeValue.java b/server/src/main/java/org/elasticsearch/common/unit/ByteSizeValue.java index d3dd414e894e1..f565b2372784b 100644 --- a/server/src/main/java/org/elasticsearch/common/unit/ByteSizeValue.java +++ b/server/src/main/java/org/elasticsearch/common/unit/ByteSizeValue.java @@ -235,10 +235,10 @@ private static ByteSizeValue parse(final String initialInput, final String norma } catch (final NumberFormatException e) { try { final double doubleValue = Double.parseDouble(s); - DeprecationLoggerHolder.deprecationLogger.deprecatedAndMaybeLog( - "fractional_byte_values", - "Fractional bytes values are deprecated. Use non-fractional bytes values instead: [{}] found for setting [{}]", - initialInput, settingName); + DeprecationLoggerHolder.deprecationLogger + .deprecate("fractional_byte_values", + "Fractional bytes values are deprecated. Use non-fractional bytes values instead: [{}] found for setting [{}]", + initialInput, settingName); return new ByteSizeValue((long) (doubleValue * unit.toBytes(1))); } catch (final NumberFormatException ignored) { throw new ElasticsearchParseException("failed to parse [{}]", e, initialInput); diff --git a/server/src/main/java/org/elasticsearch/common/xcontent/LoggingDeprecationHandler.java b/server/src/main/java/org/elasticsearch/common/xcontent/LoggingDeprecationHandler.java index 57ef66456e8ee..1aa1397a0b0dd 100644 --- a/server/src/main/java/org/elasticsearch/common/xcontent/LoggingDeprecationHandler.java +++ b/server/src/main/java/org/elasticsearch/common/xcontent/LoggingDeprecationHandler.java @@ -53,21 +53,21 @@ private LoggingDeprecationHandler() { @Override public void usedDeprecatedName(String parserName, Supplier location, String usedName, String modernName) { String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] "; - deprecationLogger.deprecatedAndMaybeLog("deprecated_field", "{}Deprecated field [{}] used, expected [{}] instead", - prefix, usedName, modernName); + deprecationLogger.deprecate("deprecated_field", + "{}Deprecated field [{}] used, expected [{}] instead", prefix, usedName, modernName); } @Override public void usedDeprecatedField(String parserName, Supplier location, String usedName, String replacedWith) { String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] "; - deprecationLogger.deprecatedAndMaybeLog("deprecated_field", "{}Deprecated field [{}] used, replaced by [{}]", - prefix, usedName, replacedWith); + deprecationLogger.deprecate("deprecated_field", + "{}Deprecated field [{}] used, replaced by [{}]", prefix, usedName, replacedWith); } @Override public void usedDeprecatedField(String parserName, Supplier location, String usedName) { String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] "; - deprecationLogger.deprecatedAndMaybeLog("deprecated_field", + deprecationLogger.deprecate("deprecated_field", "{}Deprecated field [{}] used, this field is unused and will be removed entirely", prefix, usedName); } } diff --git a/server/src/main/java/org/elasticsearch/index/analysis/ShingleTokenFilterFactory.java b/server/src/main/java/org/elasticsearch/index/analysis/ShingleTokenFilterFactory.java index 6ff289f7f79ed..8d7111a271de7 100644 --- a/server/src/main/java/org/elasticsearch/index/analysis/ShingleTokenFilterFactory.java +++ b/server/src/main/java/org/elasticsearch/index/analysis/ShingleTokenFilterFactory.java @@ -51,9 +51,9 @@ public ShingleTokenFilterFactory(IndexSettings indexSettings, Environment enviro + " must be less than or equal to: [" + maxAllowedShingleDiff + "] but was [" + shingleDiff + "]. This limit" + " can be set by changing the [" + IndexSettings.MAX_SHINGLE_DIFF_SETTING.getKey() + "] index level setting."); } else { - deprecationLogger.deprecatedAndMaybeLog("excessive_shingle_diff", + deprecationLogger.deprecate("excessive_shingle_diff", "Deprecated big difference between maxShingleSize and minShingleSize" + - " in Shingle TokenFilter, expected difference must be less than or equal to: [" + maxAllowedShingleDiff + "]"); + " in Shingle TokenFilter, expected difference must be less than or equal to: [" + maxAllowedShingleDiff + "]"); } } @@ -77,8 +77,8 @@ public TokenFilterFactory getSynonymFilter() { "] cannot be used to parse synonyms"); } else { - DEPRECATION_LOGGER.deprecatedAndMaybeLog("synonym_tokenfilters", "Token filter " + name() - + "] will not be usable to parse synonym after v7.0"); + DEPRECATION_LOGGER.deprecate("synonym_tokenfilters", "Token filter " + name() + + "] will not be usable to parse synonym after v7.0"); } return this; diff --git a/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java index 2b5b981af4e42..edd934ae119ed 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java @@ -403,11 +403,11 @@ private void checkCompletionContextsLimit(BuilderContext context) { throw new IllegalArgumentException( "Limit of completion field contexts [" + COMPLETION_CONTEXTS_LIMIT + "] has been exceeded"); } else { - deprecationLogger.deprecatedAndMaybeLog("excessive_completion_contexts", + deprecationLogger.deprecate("excessive_completion_contexts", "You have defined more than [" + COMPLETION_CONTEXTS_LIMIT + "] completion contexts" + - " in the mapping for index [" + context.indexSettings().get(IndexMetadata.SETTING_INDEX_PROVIDED_NAME) + "]. " + - "The maximum allowed number of completion contexts in a mapping will be limited to " + - "[" + COMPLETION_CONTEXTS_LIMIT + "] starting in version [8.0]."); + " in the mapping for index [" + context.indexSettings().get(IndexMetadata.SETTING_INDEX_PROVIDED_NAME) + "]. " + + "The maximum allowed number of completion contexts in a mapping will be limited to " + + "[" + COMPLETION_CONTEXTS_LIMIT + "] starting in version [8.0]."); } } } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/FieldNamesFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/FieldNamesFieldMapper.java index ab54978d39798..68523a9db9a9d 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/FieldNamesFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/FieldNamesFieldMapper.java @@ -110,7 +110,7 @@ public MetadataFieldMapper.Builder parse(String name, Map nod throw new MapperParsingException("The `enabled` setting for the `_field_names` field has been deprecated and " + "removed but is still used in index [{}]. Please remove it from your mappings and templates."); } else { - deprecationLogger.deprecatedAndMaybeLog("field_names_enabled_parameter", ENABLED_DEPRECATION_MESSAGE, indexName); + deprecationLogger.deprecate("field_names_enabled_parameter", ENABLED_DEPRECATION_MESSAGE, indexName); builder.enabled(XContentMapValues.nodeBooleanValue(fieldNode, name + ".enabled")); } iterator.remove(); @@ -179,9 +179,8 @@ public Query termQuery(Object value, QueryShardContext context) { if (isEnabled() == false) { throw new IllegalStateException("Cannot run [exists] queries if the [_field_names] field is disabled"); } - deprecationLogger.deprecatedAndMaybeLog( - "terms_query_on_field_names", - "terms query on the _field_names field is deprecated and will be removed, use exists query instead"); + deprecationLogger.deprecate("terms_query_on_field_names", + "terms query on the _field_names field is deprecated and will be removed, use exists query instead"); return super.termQuery(value, context); } } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/IdFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/IdFieldMapper.java index 89439d684b5d3..28d6c40728d2e 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/IdFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/IdFieldMapper.java @@ -182,7 +182,7 @@ public IndexFieldData build(IndexSettings indexSettings, MappedFieldType fiel + "you can re-enable it by updating the dynamic cluster setting: " + IndicesService.INDICES_ID_FIELD_DATA_ENABLED_SETTING.getKey()); } - deprecationLogger.deprecatedAndMaybeLog("id_field_data", ID_FIELD_DATA_DEPRECATION_MESSAGE); + deprecationLogger.deprecate("id_field_data", ID_FIELD_DATA_DEPRECATION_MESSAGE); final IndexFieldData fieldData = fieldDataBuilder.build(indexSettings, fieldType, cache, breakerService, mapperService); return new IndexFieldData() { diff --git a/server/src/main/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapper.java index 22968f562272d..eae3cc2a27061 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapper.java @@ -171,7 +171,7 @@ private static void checkPrefixTreeSupport(String fieldName) { throw new ElasticsearchParseException("Field parameter [{}] is not supported for [{}] field type", fieldName, CONTENT_TYPE); } - DEPRECATION_LOGGER.deprecatedAndMaybeLog("geo_mapper_field_parameter", + DEPRECATION_LOGGER.deprecate("geo_mapper_field_parameter", "Field parameter [{}] is deprecated and will be removed in a future version.", fieldName); } } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java index 412e356b111f2..aa25ebfb49047 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java @@ -199,7 +199,7 @@ protected static boolean parseObjectOrDocumentTypeProperties(String fieldName, O } return true; } else if (fieldName.equals("include_in_all")) { - deprecationLogger.deprecatedAndMaybeLog("include_in_all", + deprecationLogger.deprecate("include_in_all", "[include_in_all] is deprecated, the _all field have been removed in this version"); return true; } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java index 29a4d79582bf7..be6cb43b8a20f 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java @@ -396,7 +396,7 @@ private static void validateDynamicTemplate(Mapper.TypeParser.ParserContext pars } else { deprecationMessage = message; } - DEPRECATION_LOGGER.deprecatedAndMaybeLog("invalid_dynamic_template", deprecationMessage); + DEPRECATION_LOGGER.deprecate("invalid_dynamic_template", deprecationMessage); } } } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/TypeParsers.java b/server/src/main/java/org/elasticsearch/index/mapper/TypeParsers.java index f451909fbe481..b2f67ee03d5ac 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/TypeParsers.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/TypeParsers.java @@ -273,7 +273,7 @@ public static boolean parseMultiField(FieldMapper.Builder builder, String name, // For indices created prior to 8.0, we only emit a deprecation warning and do not fail type parsing. This is to // maintain the backwards-compatibility guarantee that we can always load indexes from the previous major version. if (parserContext.indexVersionCreated().before(Version.V_8_0_0)) { - deprecationLogger.deprecatedAndMaybeLog("multifield_within_multifield", "At least one multi-field, [" + name + "], " + + deprecationLogger.deprecate("multifield_within_multifield", "At least one multi-field, [" + name + "], " + "was encountered that itself contains a multi-field. Defining multi-fields within a multi-field is deprecated " + "and is not supported for indices created in 8.0 and later. To migrate the mappings, all instances of [fields] " + "that occur within a [fields] block should be removed from the mappings, either by flattening the chained " + diff --git a/server/src/main/java/org/elasticsearch/index/query/QueryShardContext.java b/server/src/main/java/org/elasticsearch/index/query/QueryShardContext.java index 648f4a71a4e9a..0c85ebd1852b2 100644 --- a/server/src/main/java/org/elasticsearch/index/query/QueryShardContext.java +++ b/server/src/main/java/org/elasticsearch/index/query/QueryShardContext.java @@ -234,7 +234,7 @@ public Set simpleMatchToIndexNames(String pattern) { public MappedFieldType fieldMapper(String name) { if (name.equals(TypeFieldMapper.NAME)) { - deprecationLogger.deprecatedAndMaybeLog("query_with_types", TYPES_DEPRECATION_MESSAGE); + deprecationLogger.deprecate("query_with_types", TYPES_DEPRECATION_MESSAGE); } return failIfFieldMappingNotFound(name, mapperService.fieldType(name)); } diff --git a/server/src/main/java/org/elasticsearch/index/query/functionscore/RandomScoreFunctionBuilder.java b/server/src/main/java/org/elasticsearch/index/query/functionscore/RandomScoreFunctionBuilder.java index d4b4b91e77217..3f4a2d1993a21 100644 --- a/server/src/main/java/org/elasticsearch/index/query/functionscore/RandomScoreFunctionBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/functionscore/RandomScoreFunctionBuilder.java @@ -163,8 +163,8 @@ protected ScoreFunction doToFunction(QueryShardContext context) { if (field != null) { fieldType = context.getMapperService().fieldType(field); } else { - deprecationLogger.deprecatedAndMaybeLog("seed_requires_field", - "As of version 7.0 Elasticsearch will require that a [field] parameter is provided when a [seed] is set"); + deprecationLogger.deprecate("seed_requires_field", + "As of version 7.0 Elasticsearch will require that a [field] parameter is provided when a [seed] is set"); fieldType = context.getMapperService().fieldType(IdFieldMapper.NAME); } if (fieldType == null) { diff --git a/server/src/main/java/org/elasticsearch/index/similarity/SimilarityProviders.java b/server/src/main/java/org/elasticsearch/index/similarity/SimilarityProviders.java index f534cc78df8df..c786e76c49686 100644 --- a/server/src/main/java/org/elasticsearch/index/similarity/SimilarityProviders.java +++ b/server/src/main/java/org/elasticsearch/index/similarity/SimilarityProviders.java @@ -115,8 +115,8 @@ private static BasicModel parseBasicModel(Version indexCreatedVersion, Settings throw new IllegalArgumentException("Basic model [" + basicModel + "] isn't supported anymore, " + "please use another model."); } else { - deprecationLogger.deprecatedAndMaybeLog(basicModel + "_similarity_model_replaced", "Basic model [" + basicModel + - "] isn't supported anymore and has arbitrarily been replaced with [" + replacement + "]."); + deprecationLogger.deprecate(basicModel + "_similarity_model_replaced", "Basic model [" + basicModel + + "] isn't supported anymore and has arbitrarily been replaced with [" + replacement + "]."); model = BASIC_MODELS.get(replacement); assert model != null; } @@ -146,8 +146,8 @@ private static AfterEffect parseAfterEffect(Version indexCreatedVersion, Setting throw new IllegalArgumentException("After effect [" + afterEffect + "] isn't supported anymore, please use another effect."); } else { - deprecationLogger.deprecatedAndMaybeLog(afterEffect + "_after_effect_replaced", "After effect [" + afterEffect + - "] isn't supported anymore and has arbitrarily been replaced with [" + replacement + "]."); + deprecationLogger.deprecate(afterEffect + "_after_effect_replaced", "After effect [" + afterEffect + + "] isn't supported anymore and has arbitrarily been replaced with [" + replacement + "]."); effect = AFTER_EFFECTS.get(replacement); assert effect != null; } @@ -236,7 +236,7 @@ static void assertSettingsIsSubsetOf(String type, Version version, Settings sett if (version.onOrAfter(Version.V_7_0_0)) { throw new IllegalArgumentException("Unknown settings for similarity of type [" + type + "]: " + unknownSettings); } else { - deprecationLogger.deprecatedAndMaybeLog("unknown_similarity_setting", + deprecationLogger.deprecate("unknown_similarity_setting", "Unknown settings for similarity of type [" + type + "]: " + unknownSettings); } } diff --git a/server/src/main/java/org/elasticsearch/index/similarity/SimilarityService.java b/server/src/main/java/org/elasticsearch/index/similarity/SimilarityService.java index a6a7d09848711..84e6b96daf7e4 100644 --- a/server/src/main/java/org/elasticsearch/index/similarity/SimilarityService.java +++ b/server/src/main/java/org/elasticsearch/index/similarity/SimilarityService.java @@ -124,7 +124,7 @@ public SimilarityService(IndexSettings indexSettings, ScriptService scriptServic defaultSimilarity = (providers.get("default") != null) ? providers.get("default").get() : providers.get(SimilarityService.DEFAULT_SIMILARITY).get(); if (providers.get("base") != null) { - deprecationLogger.deprecatedAndMaybeLog("base_similarity_ignored", + deprecationLogger.deprecate("base_similarity_ignored", "The [base] similarity is ignored since query normalization and coords have been removed"); } } diff --git a/server/src/main/java/org/elasticsearch/indices/analysis/AnalysisModule.java b/server/src/main/java/org/elasticsearch/indices/analysis/AnalysisModule.java index 6c54b59d474d9..9ce5b9e5e86cf 100644 --- a/server/src/main/java/org/elasticsearch/indices/analysis/AnalysisModule.java +++ b/server/src/main/java/org/elasticsearch/indices/analysis/AnalysisModule.java @@ -126,7 +126,7 @@ private NamedRegistry> setupTokenFilters(Li @Override public TokenFilterFactory get(IndexSettings indexSettings, Environment environment, String name, Settings settings) { if (indexSettings.getIndexVersionCreated().before(Version.V_7_0_0)) { - deprecationLogger.deprecatedAndMaybeLog("standard_deprecation", + deprecationLogger.deprecate("standard_deprecation", "The [standard] token filter name is deprecated and will be removed in a future version."); } else { throw new IllegalArgumentException("The [standard] token filter has been removed."); @@ -184,7 +184,7 @@ static Map setupPreConfiguredTokenFilters(List preConfiguredTokenFilters.register( "standard", PreConfiguredTokenFilter.elasticsearchVersion("standard", true, (reader, version) -> { if (version.before(Version.V_7_0_0)) { - deprecationLogger.deprecatedAndMaybeLog("standard_deprecation", + deprecationLogger.deprecate("standard_deprecation", "The [standard] token filter is deprecated and will be removed in a future version."); } else { throw new IllegalArgumentException("The [standard] token filter has been removed."); diff --git a/server/src/main/java/org/elasticsearch/ingest/ConditionalProcessor.java b/server/src/main/java/org/elasticsearch/ingest/ConditionalProcessor.java index 3ab8404034a88..cf82f23f3aa61 100644 --- a/server/src/main/java/org/elasticsearch/ingest/ConditionalProcessor.java +++ b/server/src/main/java/org/elasticsearch/ingest/ConditionalProcessor.java @@ -47,7 +47,7 @@ public class ConditionalProcessor extends AbstractProcessor implements WrappingP new DeprecationLogger(LogManager.getLogger(DynamicMap.class)); private static final Map> FUNCTIONS = Map.of( "_type", value -> { - deprecationLogger.deprecatedAndMaybeLog("conditional-processor__type", + deprecationLogger.deprecate("conditional-processor__type", "[types removal] Looking up doc types [_type] in scripts is deprecated."); return value; }); diff --git a/server/src/main/java/org/elasticsearch/node/Node.java b/server/src/main/java/org/elasticsearch/node/Node.java index 2986e15083e10..34f67ba1d8716 100644 --- a/server/src/main/java/org/elasticsearch/node/Node.java +++ b/server/src/main/java/org/elasticsearch/node/Node.java @@ -69,7 +69,7 @@ import org.elasticsearch.common.inject.ModulesBuilder; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.lease.Releasables; -import org.elasticsearch.common.logging.DeprecationLogger; +import org.elasticsearch.common.logging.HeaderWarning; import org.elasticsearch.common.logging.NodeAndClusterIdStateListener; import org.elasticsearch.common.network.NetworkAddress; import org.elasticsearch.common.network.NetworkModule; @@ -340,8 +340,8 @@ protected Node(final Environment initialEnvironment, final ResourceWatcherService resourceWatcherService = new ResourceWatcherService(settings, threadPool); resourcesToClose.add(resourceWatcherService); // adds the context to the DeprecationLogger so that it does not need to be injected everywhere - DeprecationLogger.setThreadContext(threadPool.getThreadContext()); - resourcesToClose.add(() -> DeprecationLogger.removeThreadContext(threadPool.getThreadContext())); + HeaderWarning.setThreadContext(threadPool.getThreadContext()); + resourcesToClose.add(() -> HeaderWarning.removeThreadContext(threadPool.getThreadContext())); final List> additionalSettings = new ArrayList<>(pluginsService.getPluginSettings()); final List additionalSettingsFilter = new ArrayList<>(pluginsService.getPluginSettingsFilter()); diff --git a/server/src/main/java/org/elasticsearch/rest/DeprecationRestHandler.java b/server/src/main/java/org/elasticsearch/rest/DeprecationRestHandler.java index c88fbef28a1a3..0581c77b32da8 100644 --- a/server/src/main/java/org/elasticsearch/rest/DeprecationRestHandler.java +++ b/server/src/main/java/org/elasticsearch/rest/DeprecationRestHandler.java @@ -57,7 +57,7 @@ public DeprecationRestHandler(RestHandler handler, String deprecationMessage, De */ @Override public void handleRequest(RestRequest request, RestChannel channel, NodeClient client) throws Exception { - deprecationLogger.deprecatedAndMaybeLog("deprecated_route", deprecationMessage); + deprecationLogger.deprecate("deprecated_route", deprecationMessage); handler.handleRequest(request, channel, client); } diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestSyncedFlushAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestSyncedFlushAction.java index 02d3bc3649728..642f0e34de666 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestSyncedFlushAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestSyncedFlushAction.java @@ -63,7 +63,7 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { - DEPRECATION_LOGGER.deprecatedAndMaybeLog("synced_flush", + DEPRECATION_LOGGER.deprecate("synced_flush", "Synced flush was removed and a normal flush was performed instead. This transition will be removed in a future version."); final FlushRequest flushRequest = new FlushRequest(Strings.splitStringByCommaToArray(request.param("index"))); flushRequest.indicesOptions(IndicesOptions.fromRequest(request, flushRequest.indicesOptions())); diff --git a/server/src/main/java/org/elasticsearch/script/AbstractSortScript.java b/server/src/main/java/org/elasticsearch/script/AbstractSortScript.java index 399a57038040e..2876ad65f9f7d 100644 --- a/server/src/main/java/org/elasticsearch/script/AbstractSortScript.java +++ b/server/src/main/java/org/elasticsearch/script/AbstractSortScript.java @@ -40,13 +40,13 @@ abstract class AbstractSortScript implements ScorerAware { new DeprecationLogger(LogManager.getLogger(DynamicMap.class)); private static final Map> PARAMS_FUNCTIONS = Map.of( "doc", value -> { - deprecationLogger.deprecatedAndMaybeLog("sort-script_doc", + deprecationLogger.deprecate("sort-script_doc", "Accessing variable [doc] via [params.doc] from within an sort-script " + "is deprecated in favor of directly accessing [doc]."); return value; }, "_doc", value -> { - deprecationLogger.deprecatedAndMaybeLog("sort-script__doc", + deprecationLogger.deprecate("sort-script__doc", "Accessing variable [doc] via [params._doc] from within an sort-script " + "is deprecated in favor of directly accessing [doc]."); return value; diff --git a/server/src/main/java/org/elasticsearch/script/AggregationScript.java b/server/src/main/java/org/elasticsearch/script/AggregationScript.java index f5beafb125b97..1a38797c2545a 100644 --- a/server/src/main/java/org/elasticsearch/script/AggregationScript.java +++ b/server/src/main/java/org/elasticsearch/script/AggregationScript.java @@ -44,13 +44,13 @@ public abstract class AggregationScript implements ScorerAware { new DeprecationLogger(LogManager.getLogger(DynamicMap.class)); private static final Map> PARAMS_FUNCTIONS = Map.of( "doc", value -> { - deprecationLogger.deprecatedAndMaybeLog("aggregation-script_doc", + deprecationLogger.deprecate("aggregation-script_doc", "Accessing variable [doc] via [params.doc] from within an aggregation-script " + "is deprecated in favor of directly accessing [doc]."); return value; }, "_doc", value -> { - deprecationLogger.deprecatedAndMaybeLog("aggregation-script__doc", + deprecationLogger.deprecate("aggregation-script__doc", "Accessing variable [doc] via [params._doc] from within an aggregation-script " + "is deprecated in favor of directly accessing [doc]."); return value; diff --git a/server/src/main/java/org/elasticsearch/script/FieldScript.java b/server/src/main/java/org/elasticsearch/script/FieldScript.java index ff1fd516c93e5..9d0fb613bedc1 100644 --- a/server/src/main/java/org/elasticsearch/script/FieldScript.java +++ b/server/src/main/java/org/elasticsearch/script/FieldScript.java @@ -43,13 +43,13 @@ public abstract class FieldScript { new DeprecationLogger(LogManager.getLogger(DynamicMap.class)); private static final Map> PARAMS_FUNCTIONS = Map.of( "doc", value -> { - deprecationLogger.deprecatedAndMaybeLog("field-script_doc", + deprecationLogger.deprecate("field-script_doc", "Accessing variable [doc] via [params.doc] from within an field-script " + "is deprecated in favor of directly accessing [doc]."); return value; }, "_doc", value -> { - deprecationLogger.deprecatedAndMaybeLog("field-script__doc", + deprecationLogger.deprecate("field-script__doc", "Accessing variable [doc] via [params._doc] from within an field-script " + "is deprecated in favor of directly accessing [doc]."); return value; diff --git a/server/src/main/java/org/elasticsearch/script/JodaCompatibleZonedDateTime.java b/server/src/main/java/org/elasticsearch/script/JodaCompatibleZonedDateTime.java index 1370f988ac7d1..b44d545c4d444 100644 --- a/server/src/main/java/org/elasticsearch/script/JodaCompatibleZonedDateTime.java +++ b/server/src/main/java/org/elasticsearch/script/JodaCompatibleZonedDateTime.java @@ -21,6 +21,7 @@ import org.apache.logging.log4j.LogManager; import org.elasticsearch.common.SuppressForbidden; +import org.elasticsearch.common.SuppressLoggerChecks; import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.time.DateFormatter; import org.elasticsearch.common.time.DateFormatters; @@ -59,16 +60,19 @@ */ public class JodaCompatibleZonedDateTime implements Comparable>, ChronoZonedDateTime, Temporal, TemporalAccessor { - + private static final DateFormatter DATE_FORMATTER = DateFormatter.forPattern("strict_date_time"); private static final DeprecationLogger deprecationLogger = new DeprecationLogger(LogManager.getLogger(JodaCompatibleZonedDateTime.class)); private static void logDeprecated(String key, String message, Object... params) { - // NOTE: we don't check SpecialPermission because this will be called (indirectly) from scripts - AccessController.doPrivileged((PrivilegedAction) () -> { - deprecationLogger.deprecatedAndMaybeLog(key, message, params); - return null; + AccessController.doPrivileged(new PrivilegedAction() { + @SuppressLoggerChecks(reason = "safely delegates to logger") + @Override + public Void run() { + deprecationLogger.deprecate(key, message, params); + return null; + } }); } diff --git a/server/src/main/java/org/elasticsearch/script/ScoreScript.java b/server/src/main/java/org/elasticsearch/script/ScoreScript.java index d7836998590cb..dab2b1208a955 100644 --- a/server/src/main/java/org/elasticsearch/script/ScoreScript.java +++ b/server/src/main/java/org/elasticsearch/script/ScoreScript.java @@ -69,13 +69,13 @@ public Explanation get(double score, Explanation subQueryExplanation) { new DeprecationLogger(LogManager.getLogger(DynamicMap.class)); private static final Map> PARAMS_FUNCTIONS = Map.of( "doc", value -> { - deprecationLogger.deprecatedAndMaybeLog("score-script_doc", + deprecationLogger.deprecate("score-script_doc", "Accessing variable [doc] via [params.doc] from within an score-script " + "is deprecated in favor of directly accessing [doc]."); return value; }, "_doc", value -> { - deprecationLogger.deprecatedAndMaybeLog("score-script__doc", + deprecationLogger.deprecate("score-script__doc", "Accessing variable [doc] via [params._doc] from within an score-script " + "is deprecated in favor of directly accessing [doc]."); return value; diff --git a/server/src/main/java/org/elasticsearch/script/ScriptMetadata.java b/server/src/main/java/org/elasticsearch/script/ScriptMetadata.java index 3a61494d42709..640796643e96d 100644 --- a/server/src/main/java/org/elasticsearch/script/ScriptMetadata.java +++ b/server/src/main/java/org/elasticsearch/script/ScriptMetadata.java @@ -219,9 +219,9 @@ public static ScriptMetadata fromXContent(XContentParser parser) throws IOExcept if (source.getSource().isEmpty()) { if (source.getLang().equals(Script.DEFAULT_TEMPLATE_LANG)) { - deprecationLogger.deprecatedAndMaybeLog("empty_templates","empty templates should no longer be used"); + deprecationLogger.deprecate("empty_templates", "empty templates should no longer be used"); } else { - deprecationLogger.deprecatedAndMaybeLog("empty_scripts", "empty scripts should no longer be used"); + deprecationLogger.deprecate("empty_scripts", "empty scripts should no longer be used"); } } } diff --git a/server/src/main/java/org/elasticsearch/script/ScriptedMetricAggContexts.java b/server/src/main/java/org/elasticsearch/script/ScriptedMetricAggContexts.java index 00baa6dfd50e2..d238acc12a797 100644 --- a/server/src/main/java/org/elasticsearch/script/ScriptedMetricAggContexts.java +++ b/server/src/main/java/org/elasticsearch/script/ScriptedMetricAggContexts.java @@ -70,18 +70,18 @@ public abstract static class MapScript { new DeprecationLogger(LogManager.getLogger(DynamicMap.class)); private static final Map> PARAMS_FUNCTIONS = Map.of( "doc", value -> { - deprecationLogger.deprecatedAndMaybeLog("map-script_doc", + deprecationLogger.deprecate("map-script_doc", "Accessing variable [doc] via [params.doc] from within an scripted metric agg map script " + "is deprecated in favor of directly accessing [doc]."); return value; }, "_doc", value -> { - deprecationLogger.deprecatedAndMaybeLog("map-script__doc", + deprecationLogger.deprecate("map-script__doc", "Accessing variable [doc] via [params._doc] from within an scripted metric agg map script " + "is deprecated in favor of directly accessing [doc]."); return value; }, "_agg", value -> { - deprecationLogger.deprecatedAndMaybeLog("map-script__agg", + deprecationLogger.deprecate("map-script__agg", "Accessing variable [_agg] via [params._agg] from within a scripted metric agg map script " + "is deprecated in favor of using [state]."); return value; diff --git a/server/src/main/java/org/elasticsearch/script/StoredScriptSource.java b/server/src/main/java/org/elasticsearch/script/StoredScriptSource.java index e6de5ac2d3136..d037ff0d69620 100644 --- a/server/src/main/java/org/elasticsearch/script/StoredScriptSource.java +++ b/server/src/main/java/org/elasticsearch/script/StoredScriptSource.java @@ -145,9 +145,9 @@ private StoredScriptSource build(boolean ignoreEmpty) { if (source == null) { if (ignoreEmpty || Script.DEFAULT_TEMPLATE_LANG.equals(lang)) { if (Script.DEFAULT_TEMPLATE_LANG.equals(lang)) { - deprecationLogger.deprecatedAndMaybeLog("empty_templates", "empty templates should no longer be used"); + deprecationLogger.deprecate("empty_templates", "empty templates should no longer be used"); } else { - deprecationLogger.deprecatedAndMaybeLog("empty_scripts", "empty scripts should no longer be used"); + deprecationLogger.deprecate("empty_scripts", "empty scripts should no longer be used"); } } else { throw new IllegalArgumentException("must specify source for stored script"); @@ -155,9 +155,9 @@ private StoredScriptSource build(boolean ignoreEmpty) { } else if (source.isEmpty()) { if (ignoreEmpty || Script.DEFAULT_TEMPLATE_LANG.equals(lang)) { if (Script.DEFAULT_TEMPLATE_LANG.equals(lang)) { - deprecationLogger.deprecatedAndMaybeLog("empty_templates", "empty templates should no longer be used"); + deprecationLogger.deprecate("empty_templates", "empty templates should no longer be used"); } else { - deprecationLogger.deprecatedAndMaybeLog("empty_scripts", "empty scripts should no longer be used"); + deprecationLogger.deprecate("empty_scripts", "empty scripts should no longer be used"); } } else { throw new IllegalArgumentException("source cannot be empty"); @@ -257,7 +257,7 @@ public static StoredScriptSource parse(BytesReference content, XContentType xCon token = parser.nextToken(); if (token == Token.END_OBJECT) { - deprecationLogger.deprecatedAndMaybeLog("empty_templates", "empty templates should no longer be used"); + deprecationLogger.deprecate("empty_templates", "empty templates should no longer be used"); return new StoredScriptSource(Script.DEFAULT_TEMPLATE_LANG, "", Collections.emptyMap()); } diff --git a/server/src/main/java/org/elasticsearch/script/TermsSetQueryScript.java b/server/src/main/java/org/elasticsearch/script/TermsSetQueryScript.java index 7dd2799ded29d..9a104337f9447 100644 --- a/server/src/main/java/org/elasticsearch/script/TermsSetQueryScript.java +++ b/server/src/main/java/org/elasticsearch/script/TermsSetQueryScript.java @@ -41,13 +41,13 @@ public abstract class TermsSetQueryScript { new DeprecationLogger(LogManager.getLogger(DynamicMap.class)); private static final Map> PARAMS_FUNCTIONS = Map.of( "doc", value -> { - deprecationLogger.deprecatedAndMaybeLog("terms-set-query-script_doc", + deprecationLogger.deprecate("terms-set-query-script_doc", "Accessing variable [doc] via [params.doc] from within an terms-set-query-script " + "is deprecated in favor of directly accessing [doc]."); return value; }, "_doc", value -> { - deprecationLogger.deprecatedAndMaybeLog("terms-set-query-script__doc", + deprecationLogger.deprecate("terms-set-query-script__doc", "Accessing variable [doc] via [params._doc] from within an terms-set-query-script " + "is deprecated in favor of directly accessing [doc]."); return value; diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/histogram/DateIntervalWrapper.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/histogram/DateIntervalWrapper.java index 04874c592c967..20fd8e5a0edd5 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/histogram/DateIntervalWrapper.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/histogram/DateIntervalWrapper.java @@ -137,7 +137,7 @@ public IntervalTypeEnum getIntervalType() { /** Get the current interval in milliseconds that is set on this builder. */ @Deprecated public long interval() { - DEPRECATION_LOGGER.deprecatedAndMaybeLog("date-interval-getter", DEPRECATION_TEXT); + DEPRECATION_LOGGER.deprecate("date-interval-getter", DEPRECATION_TEXT); if (intervalType.equals(IntervalTypeEnum.LEGACY_INTERVAL)) { return TimeValue.parseTimeValue(dateHistogramInterval.toString(), "interval").getMillis(); } @@ -158,14 +158,14 @@ public void interval(long interval) { throw new IllegalArgumentException("[interval] must be 1 or greater for aggregation [date_histogram]"); } setIntervalType(IntervalTypeEnum.LEGACY_INTERVAL); - DEPRECATION_LOGGER.deprecatedAndMaybeLog("date-interval-setter", DEPRECATION_TEXT); + DEPRECATION_LOGGER.deprecate("date-interval-setter", DEPRECATION_TEXT); this.dateHistogramInterval = new DateHistogramInterval(interval + "ms"); } /** Get the current date interval that is set on this builder. */ @Deprecated public DateHistogramInterval dateHistogramInterval() { - DEPRECATION_LOGGER.deprecatedAndMaybeLog("date-histogram-interval-getter", DEPRECATION_TEXT); + DEPRECATION_LOGGER.deprecate("date-histogram-interval-getter", DEPRECATION_TEXT); if (intervalType.equals(IntervalTypeEnum.LEGACY_DATE_HISTO)) { return dateHistogramInterval; } @@ -186,7 +186,7 @@ public void dateHistogramInterval(DateHistogramInterval dateHistogramInterval) { throw new IllegalArgumentException("[dateHistogramInterval] must not be null: [date_histogram]"); } setIntervalType(IntervalTypeEnum.LEGACY_DATE_HISTO); - DEPRECATION_LOGGER.deprecatedAndMaybeLog("date-histogram-interval-setter", DEPRECATION_TEXT); + DEPRECATION_LOGGER.deprecate("date-histogram-interval-setter", DEPRECATION_TEXT); this.dateHistogramInterval = dateHistogramInterval; } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/SignificantTermsAggregatorFactory.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/SignificantTermsAggregatorFactory.java index 15182218fed37..6fe8d9e1b6dfa 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/SignificantTermsAggregatorFactory.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/SignificantTermsAggregatorFactory.java @@ -413,7 +413,7 @@ public static ExecutionMode fromString(String value, final DeprecationLogger dep if ("global_ordinals".equals(value)) { return GLOBAL_ORDINALS; } else if ("global_ordinals_hash".equals(value)) { - deprecationLogger.deprecatedAndMaybeLog("global_ordinals_hash", + deprecationLogger.deprecate("global_ordinals_hash", "global_ordinals_hash is deprecated. Please use [global_ordinals] instead."); return GLOBAL_ORDINALS; } else if ("map".equals(value)) { diff --git a/server/src/main/java/org/elasticsearch/search/suggest/completion/context/GeoContextMapping.java b/server/src/main/java/org/elasticsearch/search/suggest/completion/context/GeoContextMapping.java index 79a9362745d3c..9bd855fdf1ec0 100644 --- a/server/src/main/java/org/elasticsearch/search/suggest/completion/context/GeoContextMapping.java +++ b/server/src/main/java/org/elasticsearch/search/suggest/completion/context/GeoContextMapping.java @@ -296,7 +296,7 @@ protected void validateReferences(Version indexVersionCreated, Function threadContexts = Collections.singleton(threadContext); - - final String param = randomAlphaOfLengthBetween(1, 5); - logger.deprecated(threadContexts, "A simple message [{}]", param); - - 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 [" + param + "]\"")); - } - - public void testContainingNewline() throws IOException { - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - final Set threadContexts = Collections.singleton(threadContext); - - logger.deprecated(threadContexts, "this message contains a newline\n"); - - 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("\"this message contains a newline%0A\"")); - } - - public void testSurrogatePair() throws IOException { - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - final Set threadContexts = Collections.singleton(threadContext); - - logger.deprecated(threadContexts, "this message contains a surrogate pair 😱"); - - 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); - - // convert UTF-16 to UTF-8 by hand to show the hard-coded constant below is correct - assertThat("😱", equalTo("\uD83D\uDE31")); - final int code = 0x10000 + ((0xD83D & 0x3FF) << 10) + (0xDE31 & 0x3FF); - @SuppressWarnings("PointlessBitwiseExpression") - final int[] points = new int[] { - (code >> 18) & 0x07 | 0xF0, - (code >> 12) & 0x3F | 0x80, - (code >> 6) & 0x3F | 0x80, - (code >> 0) & 0x3F | 0x80}; - final StringBuilder sb = new StringBuilder(); - // noinspection ForLoopReplaceableByForEach - for (int i = 0; i < points.length; i++) { - sb.append("%").append(Integer.toString(points[i], 16).toUpperCase(Locale.ROOT)); - } - assertThat(sb.toString(), equalTo("%F0%9F%98%B1")); - assertThat(responses.get(0), containsString("\"this message contains a surrogate pair %F0%9F%98%B1\"")); - } - - public void testAddsCombinedHeaderWithThreadContext() throws IOException { - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - final Set threadContexts = Collections.singleton(threadContext); - - final String param = randomAlphaOfLengthBetween(1, 5); - logger.deprecated(threadContexts, "A simple message [{}]", param); - final String second = randomAlphaOfLengthBetween(1, 10); - logger.deprecated(threadContexts, second); - - final Map> responseHeaders = threadContext.getResponseHeaders(); - - assertEquals(1, responseHeaders.size()); - - final List responses = responseHeaders.get("Warning"); - - assertEquals(2, responses.size()); - assertThat(responses.get(0), warningValueMatcher); - assertThat(responses.get(0), containsString("\"A simple message [" + param + "]\"")); - assertThat(responses.get(1), warningValueMatcher); - assertThat(responses.get(1), containsString("\"" + second + "\"")); - } - - public void testCanRemoveThreadContext() throws IOException { - final String expected = "testCanRemoveThreadContext"; - final String unexpected = "testCannotRemoveThreadContext"; - - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - DeprecationLogger.setThreadContext(threadContext); - logger.deprecatedAndMaybeLog("testCanRemoveThreadContext_key1", expected); - - { - final Map> responseHeaders = threadContext.getResponseHeaders(); - final List responses = responseHeaders.get("Warning"); - - assertThat(responses, hasSize(1)); - assertThat(responses.get(0), warningValueMatcher); - assertThat(responses.get(0), containsString(expected)); - } - - DeprecationLogger.removeThreadContext(threadContext); - logger.deprecatedAndMaybeLog("testCanRemoveThreadContext_key2", unexpected); - - { - final Map> responseHeaders = threadContext.getResponseHeaders(); - final List responses = responseHeaders.get("Warning"); - - assertThat(responses, hasSize(1)); - assertThat(responses.get(0), warningValueMatcher); - assertThat(responses.get(0), containsString(expected)); - assertThat(responses.get(0), not(containsString(unexpected))); - } - } - - public void testSafeWithoutThreadContext() { - logger.deprecated(Collections.emptySet(), "Ignored"); - } - - public void testFailsWithoutThreadContextSet() { - expectThrows(NullPointerException.class, () -> logger.deprecated((Set)null, "Does not explode")); - } - - public void testFailsWhenDoubleSettingSameThreadContext() throws IOException { - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - DeprecationLogger.setThreadContext(threadContext); - - try { - expectThrows(IllegalStateException.class, () -> DeprecationLogger.setThreadContext(threadContext)); - } finally { - // cleanup after ourselves - DeprecationLogger.removeThreadContext(threadContext); - } - } - - public void testFailsWhenRemovingUnknownThreadContext() throws IOException { - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - expectThrows(IllegalStateException.class, () -> DeprecationLogger.removeThreadContext(threadContext)); - } - - public void testWarningValueFromWarningHeader() { - final String s = randomAlphaOfLength(16); - final String first = DeprecationLogger.formatWarning(s); - assertThat(DeprecationLogger.extractWarningValueFromWarningHeader(first, false), equalTo(s)); - - final String withPos = "[context][1:11] Blah blah blah"; - final String formatted = DeprecationLogger.formatWarning(withPos); - assertThat(DeprecationLogger.extractWarningValueFromWarningHeader(formatted, true), equalTo("Blah blah blah")); - - final String withNegativePos = "[context][-1:-1] Blah blah blah"; - assertThat(DeprecationLogger.extractWarningValueFromWarningHeader(DeprecationLogger.formatWarning(withNegativePos), true), - equalTo("Blah blah blah")); - } - - public void testEscapeBackslashesAndQuotes() { - assertThat(DeprecationLogger.escapeBackslashesAndQuotes("\\"), equalTo("\\\\")); - assertThat(DeprecationLogger.escapeBackslashesAndQuotes("\""), equalTo("\\\"")); - assertThat(DeprecationLogger.escapeBackslashesAndQuotes("\\\""), equalTo("\\\\\\\"")); - assertThat(DeprecationLogger.escapeBackslashesAndQuotes("\"foo\\bar\""),equalTo("\\\"foo\\\\bar\\\"")); - // test that characters other than '\' and '"' are left unchanged - String chars = "\t !" + range(0x23, 0x24) + range(0x26, 0x5b) + range(0x5d, 0x73) + range(0x80, 0xff); - final String s = new CodepointSetGenerator(chars.toCharArray()).ofCodePointsLength(random(), 16, 16); - assertThat(DeprecationLogger.escapeBackslashesAndQuotes(s), equalTo(s)); - } - - public void testEncode() { - assertThat(DeprecationLogger.encode("\n"), equalTo("%0A")); - assertThat(DeprecationLogger.encode("😱"), equalTo("%F0%9F%98%B1")); - assertThat(DeprecationLogger.encode("福島深雪"), equalTo("%E7%A6%8F%E5%B3%B6%E6%B7%B1%E9%9B%AA")); - assertThat(DeprecationLogger.encode("100%\n"), equalTo("100%25%0A")); - // test that valid characters are left unchanged - String chars = "\t !" + range(0x23, 0x24) + range(0x26, 0x5b) + range(0x5d, 0x73) + range(0x80, 0xff) + '\\' + '"'; - final String s = new CodepointSetGenerator(chars.toCharArray()).ofCodePointsLength(random(), 16, 16); - assertThat(DeprecationLogger.encode(s), equalTo(s)); - // when no encoding is needed, the original string is returned (optimization) - assertThat(DeprecationLogger.encode(s), IsSame.sameInstance(s)); - } - - - public void testWarningHeaderCountSetting() throws IOException{ - // Test that the number of warning headers don't exceed 'http.max_warning_header_count' - 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); - // try to log three warning messages - logger.deprecated(threadContexts, "A simple message 1"); - logger.deprecated(threadContexts, "A simple message 2"); - logger.deprecated(threadContexts, "A simple message 3"); - final Map> responseHeaders = threadContext.getResponseHeaders(); - final List responses = responseHeaders.get("Warning"); - - assertEquals(maxWarningHeaderCount, responses.size()); - assertThat(responses.get(0), warningValueMatcher); - assertThat(responses.get(0), containsString("\"A simple message 1")); - assertThat(responses.get(1), warningValueMatcher); - assertThat(responses.get(1), containsString("\"A simple message 2")); - } - - public void testWarningHeaderSizeSetting() throws IOException{ - // Test that the size of warning headers don't exceed 'http.max_warning_header_size' - Settings settings = Settings.builder() - .put("http.max_warning_header_size", "1Kb") - .build(); - - byte [] arr = new byte[300]; - String message1 = new String(arr, StandardCharsets.UTF_8) + "1"; - String message2 = new String(arr, StandardCharsets.UTF_8) + "2"; - String message3 = new String(arr, StandardCharsets.UTF_8) + "3"; - - ThreadContext threadContext = new ThreadContext(settings); - final Set threadContexts = Collections.singleton(threadContext); - // try to log three warning messages - logger.deprecated(threadContexts, message1); - logger.deprecated(threadContexts, message2); - logger.deprecated(threadContexts, message3); - final Map> responseHeaders = threadContext.getResponseHeaders(); - final List responses = responseHeaders.get("Warning"); - - long warningHeadersSize = 0L; - for (String response : responses){ - warningHeadersSize += "Warning".getBytes(StandardCharsets.UTF_8).length + - response.getBytes(StandardCharsets.UTF_8).length; - } - // assert that the size of all warning headers is less or equal to 1Kb - assertTrue(warningHeadersSize <= 1024); - } @SuppressLoggerChecks(reason = "Safe as this is using mockito") public void testLogPermissions() { AtomicBoolean supplierCalled = new AtomicBoolean(false); @@ -340,20 +79,15 @@ public LoggerContext getContext(String fqcn, ClassLoader loader, Object external new ProtectionDomain[]{new ProtectionDomain(null, new Permissions())} ); AccessController.doPrivileged((PrivilegedAction) () -> { - deprecationLogger.deprecatedAndMaybeLog("testLogPermissions_key", "foo", "bar"); + deprecationLogger.deprecate("testLogPermissions_key", "foo {}", "bar"); return null; }, noPermissionsAcc); assertThat("supplier called", supplierCalled.get(), is(true)); + + assertWarnings("foo bar"); } finally { LogManager.setFactory(originalFactory); } } - private String range(int lowerInclusive, int upperInclusive) { - return IntStream - .range(lowerInclusive, upperInclusive + 1) - .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) - .toString(); - } - } diff --git a/server/src/test/java/org/elasticsearch/common/logging/HeaderWarningTests.java b/server/src/test/java/org/elasticsearch/common/logging/HeaderWarningTests.java new file mode 100644 index 0000000000000..56cf86d2e7642 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/common/logging/HeaderWarningTests.java @@ -0,0 +1,299 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.elasticsearch.common.logging; + +import com.carrotsearch.randomizedtesting.generators.CodepointSetGenerator; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.hamcrest.RegexMatcher; +import org.hamcrest.core.IsSame; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.IntStream; + +import static org.elasticsearch.common.logging.HeaderWarning.WARNING_HEADER_PATTERN; +import static org.elasticsearch.test.hamcrest.RegexMatcher.matches; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.not; + +/** + * Tests {@link HeaderWarning} + */ +public class HeaderWarningTests extends ESTestCase { + + private static final RegexMatcher warningValueMatcher = matches(WARNING_HEADER_PATTERN.pattern()); + + private final HeaderWarning logger = new HeaderWarning(); + + @Override + protected boolean enableWarningsCheck() { + //this is a low level test for the deprecation logger, setup and checks are done manually + return false; + } + + public void testAddsHeaderWithThreadContext() throws IOException { + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + final Set threadContexts = Collections.singleton(threadContext); + + final String param = randomAlphaOfLengthBetween(1, 5); + HeaderWarning.addWarning(threadContexts, "A simple message [{}]", param); + + 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 [" + param + "]\"")); + } + + public void testContainingNewline() throws IOException { + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + final Set threadContexts = Collections.singleton(threadContext); + + HeaderWarning.addWarning(threadContexts, "this message contains a newline\n"); + + 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("\"this message contains a newline%0A\"")); + } + + public void testSurrogatePair() throws IOException { + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + final Set threadContexts = Collections.singleton(threadContext); + + HeaderWarning.addWarning(threadContexts, "this message contains a surrogate pair 😱"); + + 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); + + // convert UTF-16 to UTF-8 by hand to show the hard-coded constant below is correct + assertThat("😱", equalTo("\uD83D\uDE31")); + final int code = 0x10000 + ((0xD83D & 0x3FF) << 10) + (0xDE31 & 0x3FF); + @SuppressWarnings("PointlessBitwiseExpression") + final int[] points = new int[] { + (code >> 18) & 0x07 | 0xF0, + (code >> 12) & 0x3F | 0x80, + (code >> 6) & 0x3F | 0x80, + (code >> 0) & 0x3F | 0x80}; + final StringBuilder sb = new StringBuilder(); + // noinspection ForLoopReplaceableByForEach + for (int i = 0; i < points.length; i++) { + sb.append("%").append(Integer.toString(points[i], 16).toUpperCase(Locale.ROOT)); + } + assertThat(sb.toString(), equalTo("%F0%9F%98%B1")); + assertThat(responses.get(0), containsString("\"this message contains a surrogate pair %F0%9F%98%B1\"")); + } + + public void testAddsCombinedHeaderWithThreadContext() throws IOException { + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + final Set threadContexts = Collections.singleton(threadContext); + + final String param = randomAlphaOfLengthBetween(1, 5); + HeaderWarning.addWarning(threadContexts, "A simple message [{}]", param); + final String second = randomAlphaOfLengthBetween(1, 10); + HeaderWarning.addWarning(threadContexts, second); + + final Map> responseHeaders = threadContext.getResponseHeaders(); + + assertEquals(1, responseHeaders.size()); + + final List responses = responseHeaders.get("Warning"); + + assertEquals(2, responses.size()); + assertThat(responses.get(0), warningValueMatcher); + assertThat(responses.get(0), containsString("\"A simple message [" + param + "]\"")); + assertThat(responses.get(1), warningValueMatcher); + assertThat(responses.get(1), containsString("\"" + second + "\"")); + } + + public void testCanRemoveThreadContext() throws IOException { + final String expected = "testCanRemoveThreadContext"; + final String unexpected = "testCannotRemoveThreadContext"; + + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + HeaderWarning.setThreadContext(threadContext); + /*"testCanRemoveThreadContext_key1",*/ + HeaderWarning.addWarning(HeaderWarning.THREAD_CONTEXT, expected); + + { + final Map> responseHeaders = threadContext.getResponseHeaders(); + final List responses = responseHeaders.get("Warning"); + + assertThat(responses, hasSize(1)); + assertThat(responses.get(0), warningValueMatcher); + assertThat(responses.get(0), containsString(expected)); + } + + HeaderWarning.removeThreadContext(threadContext); + /*"testCanRemoveThreadContext_key2", */ + HeaderWarning.addWarning(HeaderWarning.THREAD_CONTEXT, unexpected); + + { + final Map> responseHeaders = threadContext.getResponseHeaders(); + final List responses = responseHeaders.get("Warning"); + + assertThat(responses, hasSize(1)); + assertThat(responses.get(0), warningValueMatcher); + assertThat(responses.get(0), containsString(expected)); + assertThat(responses.get(0), not(containsString(unexpected))); + } + } + + public void testSafeWithoutThreadContext() { + HeaderWarning.addWarning(Collections.emptySet(), "Ignored"); + } + + public void testFailsWithoutThreadContextSet() { + expectThrows(NullPointerException.class, + () -> HeaderWarning.addWarning((Set)null, "Does not explode")); + } + + public void testFailsWhenDoubleSettingSameThreadContext() throws IOException { + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + HeaderWarning.setThreadContext(threadContext); + + try { + expectThrows(IllegalStateException.class, () -> HeaderWarning.setThreadContext(threadContext)); + } finally { + // cleanup after ourselves + HeaderWarning.removeThreadContext(threadContext); + } + } + + public void testFailsWhenRemovingUnknownThreadContext() throws IOException { + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + expectThrows(IllegalStateException.class, () -> HeaderWarning.removeThreadContext(threadContext)); + } + + public void testWarningValueFromWarningHeader() { + final String s = randomAlphaOfLength(16); + final String first = HeaderWarning.formatWarning(s); + assertThat(HeaderWarning.extractWarningValueFromWarningHeader(first, false), equalTo(s)); + + final String withPos = "[context][1:11] Blah blah blah"; + final String formatted = HeaderWarning.formatWarning(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")); + } + + public void testEscapeBackslashesAndQuotes() { + assertThat(HeaderWarning.escapeBackslashesAndQuotes("\\"), equalTo("\\\\")); + assertThat(HeaderWarning.escapeBackslashesAndQuotes("\""), equalTo("\\\"")); + assertThat(HeaderWarning.escapeBackslashesAndQuotes("\\\""), equalTo("\\\\\\\"")); + assertThat(HeaderWarning.escapeBackslashesAndQuotes("\"foo\\bar\""),equalTo("\\\"foo\\\\bar\\\"")); + // test that characters other than '\' and '"' are left unchanged + String chars = "\t !" + range(0x23, 0x24) + range(0x26, 0x5b) + range(0x5d, 0x73) + range(0x80, 0xff); + final String s = new CodepointSetGenerator(chars.toCharArray()).ofCodePointsLength(random(), 16, 16); + assertThat(HeaderWarning.escapeBackslashesAndQuotes(s), equalTo(s)); + } + + public void testEncode() { + assertThat(HeaderWarning.encode("\n"), equalTo("%0A")); + assertThat(HeaderWarning.encode("😱"), equalTo("%F0%9F%98%B1")); + assertThat(HeaderWarning.encode("福島深雪"), equalTo("%E7%A6%8F%E5%B3%B6%E6%B7%B1%E9%9B%AA")); + assertThat(HeaderWarning.encode("100%\n"), equalTo("100%25%0A")); + // test that valid characters are left unchanged + String chars = "\t !" + range(0x23, 0x24) + range(0x26, 0x5b) + range(0x5d, 0x73) + range(0x80, 0xff) + '\\' + '"'; + final String s = new CodepointSetGenerator(chars.toCharArray()).ofCodePointsLength(random(), 16, 16); + assertThat(HeaderWarning.encode(s), equalTo(s)); + // when no encoding is needed, the original string is returned (optimization) + assertThat(HeaderWarning.encode(s), IsSame.sameInstance(s)); + } + + + public void testWarningHeaderCountSetting() throws IOException{ + // Test that the number of warning headers don't exceed 'http.max_warning_header_count' + 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); + // try to log three warning messages + HeaderWarning.addWarning(threadContexts, "A simple message 1"); + HeaderWarning.addWarning(threadContexts, "A simple message 2"); + HeaderWarning.addWarning(threadContexts, "A simple message 3"); + final Map> responseHeaders = threadContext.getResponseHeaders(); + final List responses = responseHeaders.get("Warning"); + + assertEquals(maxWarningHeaderCount, responses.size()); + assertThat(responses.get(0), warningValueMatcher); + assertThat(responses.get(0), containsString("\"A simple message 1")); + assertThat(responses.get(1), warningValueMatcher); + assertThat(responses.get(1), containsString("\"A simple message 2")); + } + + public void testWarningHeaderSizeSetting() throws IOException{ + // Test that the size of warning headers don't exceed 'http.max_warning_header_size' + Settings settings = Settings.builder() + .put("http.max_warning_header_size", "1Kb") + .build(); + + byte [] arr = new byte[300]; + String message1 = new String(arr, StandardCharsets.UTF_8) + "1"; + String message2 = new String(arr, StandardCharsets.UTF_8) + "2"; + String message3 = new String(arr, StandardCharsets.UTF_8) + "3"; + + ThreadContext threadContext = new ThreadContext(settings); + final Set threadContexts = Collections.singleton(threadContext); + // try to log three warning messages + HeaderWarning.addWarning(threadContexts, message1); + HeaderWarning.addWarning(threadContexts, message2); + HeaderWarning.addWarning(threadContexts, message3); + final Map> responseHeaders = threadContext.getResponseHeaders(); + final List responses = responseHeaders.get("Warning"); + + long warningHeadersSize = 0L; + for (String response : responses){ + warningHeadersSize += "Warning".getBytes(StandardCharsets.UTF_8).length + + response.getBytes(StandardCharsets.UTF_8).length; + } + // assert that the size of all warning headers is less or equal to 1Kb + assertTrue(warningHeadersSize <= 1024); + } + + private String range(int lowerInclusive, int upperInclusive) { + return IntStream + .range(lowerInclusive, upperInclusive + 1) + .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) + .toString(); + } + +} 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 a2a456916e4d6..c9315824ba6c8 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 @@ -19,7 +19,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; @@ -29,6 +29,7 @@ import java.util.List; import java.util.Map; import java.util.function.Supplier; + import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasSize; @@ -203,12 +204,12 @@ public void testResponseHeaders() { threadContext.addResponseHeader("foo", "bar"); } - final String value = DeprecationLogger.formatWarning("qux"); - threadContext.addResponseHeader("baz", value, s -> DeprecationLogger.extractWarningValueFromWarningHeader(s, false)); + final String value = HeaderWarning.formatWarning("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 = DeprecationLogger.formatWarning("qux"); - threadContext.addResponseHeader("baz", duplicateValue, s -> DeprecationLogger.extractWarningValueFromWarningHeader(s, false)); + final String duplicateValue = HeaderWarning.formatWarning("qux"); + threadContext.addResponseHeader("baz", duplicateValue, s -> HeaderWarning.extractWarningValueFromWarningHeader(s, false)); } threadContext.addResponseHeader("Warning", "One is the loneliest number"); diff --git a/server/src/test/java/org/elasticsearch/index/analysis/AnalysisRegistryTests.java b/server/src/test/java/org/elasticsearch/index/analysis/AnalysisRegistryTests.java index e2d4d5b4407ff..adb0b17d86ba7 100644 --- a/server/src/test/java/org/elasticsearch/index/analysis/AnalysisRegistryTests.java +++ b/server/src/test/java/org/elasticsearch/index/analysis/AnalysisRegistryTests.java @@ -20,7 +20,6 @@ package org.elasticsearch.index.analysis; import com.carrotsearch.randomizedtesting.generators.RandomPicks; - import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.MockTokenFilter; import org.apache.lucene.analysis.TokenStream; @@ -325,7 +324,7 @@ class MockFactory extends AbstractTokenFilterFactory { @Override public TokenStream create(TokenStream tokenStream) { if (indexSettings.getIndexVersionCreated().equals(Version.CURRENT)) { - deprecationLogger.deprecatedAndMaybeLog("deprecated_token_filter", "Using deprecated token filter [deprecated]"); + deprecationLogger.deprecate("deprecated_token_filter", "Using deprecated token filter [deprecated]"); } return tokenStream; } @@ -353,7 +352,7 @@ class UnusedMockFactory extends AbstractTokenFilterFactory { @Override public TokenStream create(TokenStream tokenStream) { - deprecationLogger.deprecatedAndMaybeLog("unused_token_filter", "Using deprecated token filter [unused]"); + deprecationLogger.deprecate("unused_token_filter", "Using deprecated token filter [unused]"); return tokenStream; } } @@ -366,8 +365,7 @@ class NormalizerFactory extends AbstractTokenFilterFactory implements Normalizin @Override public TokenStream create(TokenStream tokenStream) { - deprecationLogger.deprecatedAndMaybeLog("deprecated_normalizer", - "Using deprecated token filter [deprecated_normalizer]"); + deprecationLogger.deprecate("deprecated_normalizer", "Using deprecated token filter [deprecated_normalizer]"); return tokenStream; } diff --git a/server/src/test/java/org/elasticsearch/rest/DeprecationRestHandlerTests.java b/server/src/test/java/org/elasticsearch/rest/DeprecationRestHandlerTests.java index cbce81f7d2f40..399c3cfcd5453 100644 --- a/server/src/test/java/org/elasticsearch/rest/DeprecationRestHandlerTests.java +++ b/server/src/test/java/org/elasticsearch/rest/DeprecationRestHandlerTests.java @@ -77,7 +77,7 @@ public void testHandleRequestLogsWarningThenForwards() throws Exception { InOrder inOrder = inOrder(handler, request, channel, deprecationLogger); // log, then forward - inOrder.verify(deprecationLogger).deprecatedAndMaybeLog("deprecated_route", deprecationMessage); + inOrder.verify(deprecationLogger).deprecate("deprecated_route", deprecationMessage); inOrder.verify(handler).handleRequest(request, channel, client); inOrder.verifyNoMoreInteractions(); } 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 2eb761af73ce5..4f52c6ee47372 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java @@ -65,7 +65,7 @@ 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.LogConfigurator; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Setting; @@ -341,7 +341,7 @@ public final void before() { assertNull("Thread context initialized twice", threadContext); if (enableWarningsCheck()) { this.threadContext = new ThreadContext(Settings.EMPTY); - DeprecationLogger.setThreadContext(threadContext); + HeaderWarning.setThreadContext(threadContext); } } @@ -372,7 +372,7 @@ public final void after() throws Exception { // initialized if (threadContext != null) { ensureNoWarnings(); - DeprecationLogger.removeThreadContext(threadContext); + HeaderWarning.removeThreadContext(threadContext); threadContext = null; } ensureAllSearchContextsReleased(); @@ -433,10 +433,10 @@ protected final void assertWarnings(boolean stripXContentPosition, String... exp final List actualWarnings = threadContext.getResponseHeaders().get("Warning"); assertNotNull("no warnings, expected: " + Arrays.asList(expectedWarnings), actualWarnings); final Set actualWarningValues = - actualWarnings.stream().map(s -> DeprecationLogger.extractWarningValueFromWarningHeader(s, stripXContentPosition)) + actualWarnings.stream().map(s -> HeaderWarning.extractWarningValueFromWarningHeader(s, stripXContentPosition)) .collect(Collectors.toSet()); for (String msg : expectedWarnings) { - assertThat(actualWarningValues, hasItem(DeprecationLogger.escapeAndEncode(msg))); + assertThat(actualWarningValues, hasItem(HeaderWarning.escapeAndEncode(msg))); } assertEquals("Expected " + expectedWarnings.length + " warnings but found " + actualWarnings.size() + "\nExpected: " + Arrays.asList(expectedWarnings) + "\nActual: " + actualWarnings, diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/DoSection.java b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/DoSection.java index d7884dd79d510..78aff9e542d6e 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/DoSection.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/section/DoSection.java @@ -28,7 +28,7 @@ import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.Strings; import org.elasticsearch.common.collect.Tuple; -import org.elasticsearch.common.logging.DeprecationLogger; +import org.elasticsearch.common.logging.HeaderWarning; import org.elasticsearch.common.xcontent.DeprecationHandler; import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.XContentLocation; @@ -56,7 +56,6 @@ import static java.util.stream.Collectors.toCollection; import static java.util.stream.Collectors.toSet; import static org.elasticsearch.common.collect.Tuple.tuple; -import static org.elasticsearch.common.logging.DeprecationLogger.WARNING_HEADER_PATTERN; import static org.elasticsearch.test.hamcrest.RegexMatcher.matches; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.equalTo; @@ -321,17 +320,17 @@ void checkWarningHeaders(final List warningHeaders, final Version master final List unmatched = new ArrayList<>(); final List missing = new ArrayList<>(); Set allowed = allowedWarningHeaders.stream() - .map(DeprecationLogger::escapeAndEncode) + .map(HeaderWarning::escapeAndEncode) .collect(toSet()); // LinkedHashSet so that missing expected warnings come back in a predictable order which is nice for testing final Set expected = expectedWarningHeaders.stream() - .map(DeprecationLogger::escapeAndEncode) + .map(HeaderWarning::escapeAndEncode) .collect(toCollection(LinkedHashSet::new)); for (final String header : warningHeaders) { - final Matcher matcher = WARNING_HEADER_PATTERN.matcher(header); + final Matcher matcher = HeaderWarning.WARNING_HEADER_PATTERN.matcher(header); final boolean matches = matcher.matches(); if (matches) { - final String message = DeprecationLogger.extractWarningValueFromWarningHeader(header, true); + final String message = HeaderWarning.extractWarningValueFromWarningHeader(header, true); if (allowed.contains(message)) { continue; } 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 ea0be9a018c3a..8d83f8b4b407a 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 @@ -24,7 +24,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.common.xcontent.XContentLocation; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.yaml.YamlXContent; @@ -61,10 +61,10 @@ public void testWarningHeaders() { section.checkWarningHeaders(emptyList(), Version.CURRENT); } - final String testHeader = DeprecationLogger.formatWarning("test"); - final String anotherHeader = DeprecationLogger.formatWarning("another"); - final String someMoreHeader = DeprecationLogger.formatWarning("some more"); - final String catHeader = DeprecationLogger.formatWarning("cat"); + final String testHeader = HeaderWarning.formatWarning("test"); + final String anotherHeader = HeaderWarning.formatWarning("another"); + final String someMoreHeader = HeaderWarning.formatWarning("some more"); + final String catHeader = HeaderWarning.formatWarning("cat"); // Any warning headers fail { final DoSection section = new DoSection(new XContentLocation(1, 1)); diff --git a/test/logger-usage/src/main/java/org/elasticsearch/test/loggerusage/ESLoggerUsageChecker.java b/test/logger-usage/src/main/java/org/elasticsearch/test/loggerusage/ESLoggerUsageChecker.java index 5241514c909f5..efa05de13681f 100644 --- a/test/logger-usage/src/main/java/org/elasticsearch/test/loggerusage/ESLoggerUsageChecker.java +++ b/test/logger-usage/src/main/java/org/elasticsearch/test/loggerusage/ESLoggerUsageChecker.java @@ -273,27 +273,8 @@ public void findBadLoggerUsages(MethodNode methodNode) { int lengthWithoutMarker = argumentTypes.length - markerOffset; - if (lengthWithoutMarker == 2 && - argumentTypes[markerOffset + 0].equals(STRING_CLASS) && - (argumentTypes[markerOffset + 1].equals(OBJECT_ARRAY_CLASS) || - argumentTypes[markerOffset + 1].equals(SUPPLIER_ARRAY_CLASS))) { - // VARARGS METHOD: debug(Marker?, String, (Object...|Supplier...)) - checkArrayArgs(methodNode, logMessageFrames[i], arraySizeFrames[i], lineNumber, methodInsn, markerOffset + 0, - markerOffset + 1); - } else if (lengthWithoutMarker >= 2 && - argumentTypes[markerOffset + 0].equals(STRING_CLASS) && - argumentTypes[markerOffset + 1].equals(OBJECT_CLASS)) { - // MULTI-PARAM METHOD: debug(Marker?, String, Object p0, ...) - checkFixedArityArgs(methodNode, logMessageFrames[i], lineNumber, methodInsn, markerOffset + 0, - lengthWithoutMarker - 1); - } else if ((lengthWithoutMarker == 1 || lengthWithoutMarker == 2) && - lengthWithoutMarker == 2 ? argumentTypes[markerOffset + 1].equals(THROWABLE_CLASS) : true) { - // all the rest: debug(Marker?, (Message|MessageSupplier|CharSequence|Object|String|Supplier), Throwable?) - checkFixedArityArgs(methodNode, logMessageFrames[i], lineNumber, methodInsn, markerOffset + 0, 0); - } else { - throw new IllegalStateException("Method invoked on " + LOGGER_CLASS.getClassName() + - " that is not supported by logger usage checker"); - } + verifyLoggerUsage(methodNode, logMessageFrames, arraySizeFrames, lineNumber, i, + methodInsn, argumentTypes, markerOffset, lengthWithoutMarker); } } else if (insn.getOpcode() == Opcodes.INVOKESPECIAL) { // constructor invocation MethodInsnNode methodInsn = (MethodInsnNode) insn; @@ -338,10 +319,51 @@ public void findBadLoggerUsages(MethodNode methodNode) { "Constructor: "+ Arrays.toString(argumentTypes))); } } + } else if (insn.getOpcode() == Opcodes.INVOKEVIRTUAL) { + //using strings because this test do not depend on server + + MethodInsnNode methodInsn = (MethodInsnNode) insn; + if (methodInsn.owner.equals("org/elasticsearch/common/logging/DeprecationLogger")) { + if (methodInsn.name.equals("deprecate")) { + Type[] argumentTypes = Type.getArgumentTypes(methodInsn.desc); + int markerOffset = 1; // skip key + + int lengthWithoutMarker = argumentTypes.length - markerOffset; + + verifyLoggerUsage(methodNode, logMessageFrames, arraySizeFrames, lineNumber, i, + methodInsn, argumentTypes, markerOffset, lengthWithoutMarker); + } + } } } } + private void verifyLoggerUsage(MethodNode methodNode, Frame[] logMessageFrames, Frame[] arraySizeFrames, + int lineNumber, int i, MethodInsnNode methodInsn, Type[] argumentTypes, + int markerOffset, int lengthWithoutMarker) { + if (lengthWithoutMarker == 2 && + argumentTypes[markerOffset + 0].equals(STRING_CLASS) && + (argumentTypes[markerOffset + 1].equals(OBJECT_ARRAY_CLASS) || + argumentTypes[markerOffset + 1].equals(SUPPLIER_ARRAY_CLASS))) { + // VARARGS METHOD: debug(Marker?, String, (Object...|Supplier...)) + checkArrayArgs(methodNode, logMessageFrames[i], arraySizeFrames[i], lineNumber, methodInsn, markerOffset + 0, + markerOffset + 1); + } else if (lengthWithoutMarker >= 2 && + argumentTypes[markerOffset + 0].equals(STRING_CLASS) && + argumentTypes[markerOffset + 1].equals(OBJECT_CLASS)) { + // MULTI-PARAM METHOD: debug(Marker?, String, Object p0, ...) + checkFixedArityArgs(methodNode, logMessageFrames[i], lineNumber, methodInsn, markerOffset + 0, + lengthWithoutMarker - 1); + } else if ((lengthWithoutMarker == 1 || lengthWithoutMarker == 2) && + lengthWithoutMarker == 2 ? argumentTypes[markerOffset + 1].equals(THROWABLE_CLASS) : true) { + // all the rest: debug(Marker?, (Message|MessageSupplier|CharSequence|Object|String|Supplier), Throwable?) + checkFixedArityArgs(methodNode, logMessageFrames[i], lineNumber, methodInsn, markerOffset + 0, 0); + } else { + throw new IllegalStateException("Method invoked on " + LOGGER_CLASS.getClassName() + + " that is not supported by logger usage checker"); + } + } + private void checkFixedArityArgs(MethodNode methodNode, Frame logMessageFrame, int lineNumber, MethodInsnNode methodInsn, int messageIndex, int positionalArgsLength) { PlaceHolderStringBasicValue logMessageLength = checkLogMessageConsistency(methodNode, logMessageFrame, lineNumber, methodInsn, diff --git a/test/logger-usage/src/test/java/org/elasticsearch/test/loggerusage/ESLoggerUsageTests.java b/test/logger-usage/src/test/java/org/elasticsearch/test/loggerusage/ESLoggerUsageTests.java index 6ca52f38c5670..1740022f1374b 100644 --- a/test/logger-usage/src/test/java/org/elasticsearch/test/loggerusage/ESLoggerUsageTests.java +++ b/test/logger-usage/src/test/java/org/elasticsearch/test/loggerusage/ESLoggerUsageTests.java @@ -26,6 +26,7 @@ import org.apache.logging.log4j.util.MessageSupplier; import org.apache.logging.log4j.util.Supplier; import org.elasticsearch.common.SuppressLoggerChecks; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.logging.ESLogMessage; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.loggerusage.ESLoggerUsageChecker.WrongLoggerUsage; @@ -131,6 +132,7 @@ public void checkWithUsage() { .with("field2", "value2")); } + public void checkFailArraySizeForSubclasses(Object... arr) { logger.debug(new ESLogMessage("message {}", arr)); } @@ -259,4 +261,9 @@ public void checkFailComplexUsage2(boolean b) { logger.info(message, args); } + public void checkDeprecationLogger() { + DeprecationLogger deprecationLogger = new DeprecationLogger(logger); + deprecationLogger.deprecate("key","message {}", 123); + } + } diff --git a/x-pack/plugin/async-search/qa/rest/src/main/java/org/elasticsearch/query/DeprecatedQueryBuilder.java b/x-pack/plugin/async-search/qa/rest/src/main/java/org/elasticsearch/query/DeprecatedQueryBuilder.java index db5ec14dcbd91..7e1f5fdc9e475 100644 --- a/x-pack/plugin/async-search/qa/rest/src/main/java/org/elasticsearch/query/DeprecatedQueryBuilder.java +++ b/x-pack/plugin/async-search/qa/rest/src/main/java/org/elasticsearch/query/DeprecatedQueryBuilder.java @@ -54,7 +54,7 @@ public static DeprecatedQueryBuilder fromXContent(XContentParser parser) { @Override protected Query doToQuery(QueryShardContext context) { - deprecationLogger.deprecatedAndMaybeLog("to_query", "[deprecated] query"); + deprecationLogger.deprecate("to_query", "[deprecated] query"); return new MatchAllDocsQuery(); } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetLicenseAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetLicenseAction.java index 0093d8dee6a63..b08f3b97e38eb 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetLicenseAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/RestGetLicenseAction.java @@ -58,9 +58,9 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC // In 7.x, there was an opt-in flag to show "enterprise" licenses. In 8.0 the flag is deprecated and can only be true // TODO Remove this from 9.0 if (request.hasParam("accept_enterprise")) { - deprecationLogger.deprecatedAndMaybeLog("get_license_accept_enterprise", + deprecationLogger.deprecate("get_license_accept_enterprise", "Including [accept_enterprise] in get license requests is deprecated." + - " The parameter will be removed in the next major version"); + " The parameter will be removed in the next major version"); if (request.paramAsBoolean("accept_enterprise", true) == false) { throw new IllegalArgumentException("The [accept_enterprise] parameters may not be false"); } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java index efeedaa2a0e6b..cf9a1f0a7d7fb 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java @@ -311,7 +311,7 @@ public static Path resolveConfigFile(Environment env, String name) { if (Files.exists(config) == false) { Path legacyConfig = env.configFile().resolve("x-pack").resolve(name); if (Files.exists(legacyConfig)) { - deprecationLogger.deprecatedAndMaybeLog("config_file_path", + deprecationLogger.deprecate("config_file_path", "Config file [" + name + "] is in a deprecated location. Move from " + legacyConfig.toString() + " to " + config.toString()); return legacyConfig; diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/action/GetTransformAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/action/GetTransformAction.java index b16b0adec9d15..a8457092d1f1e 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/action/GetTransformAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/action/GetTransformAction.java @@ -117,11 +117,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.field(TransformField.COUNT.getPreferredName(), invalidTransforms.size()); builder.field(TransformField.TRANSFORMS.getPreferredName(), invalidTransforms); builder.endObject(); - deprecationLogger.deprecatedAndMaybeLog( - "invalid_transforms", - INVALID_TRANSFORMS_DEPRECATION_WARNING, - invalidTransforms.size() - ); + deprecationLogger.deprecate("invalid_transforms", INVALID_TRANSFORMS_DEPRECATION_WARNING, invalidTransforms.size()); } builder.endObject(); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/transforms/pivot/PivotConfig.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/transforms/pivot/PivotConfig.java index 64bb0f43d12e3..5c02cf2808791 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/transforms/pivot/PivotConfig.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/transforms/pivot/PivotConfig.java @@ -84,7 +84,7 @@ public PivotConfig(final GroupConfig groups, final AggregationConfig aggregation this.maxPageSearchSize = maxPageSearchSize; if (maxPageSearchSize != null) { - deprecationLogger.deprecatedAndMaybeLog( + deprecationLogger.deprecate( TransformField.MAX_PAGE_SEARCH_SIZE.getPreferredName(), "[max_page_search_size] is deprecated inside pivot please use settings instead" ); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/transform/transforms/MockDeprecatedAggregationBuilder.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/transform/transforms/MockDeprecatedAggregationBuilder.java index 8ba1dc29ed7f9..995b5efa22c37 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/transform/transforms/MockDeprecatedAggregationBuilder.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/transform/transforms/MockDeprecatedAggregationBuilder.java @@ -87,7 +87,7 @@ protected XContentBuilder doXContentBody(XContentBuilder builder, Params params) } public static MockDeprecatedAggregationBuilder fromXContent(XContentParser p) { - deprecationLogger.deprecatedAndMaybeLog("deprecated_mock", DEPRECATION_MESSAGE); + deprecationLogger.deprecate("deprecated_mock", DEPRECATION_MESSAGE); return new MockDeprecatedAggregationBuilder(); } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/transform/transforms/MockDeprecatedQueryBuilder.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/transform/transforms/MockDeprecatedQueryBuilder.java index 712354091450e..b03f42ab188a7 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/transform/transforms/MockDeprecatedQueryBuilder.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/transform/transforms/MockDeprecatedQueryBuilder.java @@ -47,7 +47,7 @@ public MockDeprecatedQueryBuilder(StreamInput in) throws IOException { public static MockDeprecatedQueryBuilder fromXContent(XContentParser parser) { try { - deprecationLogger.deprecatedAndMaybeLog("deprecated_mock", DEPRECATION_MESSAGE); + deprecationLogger.deprecate("deprecated_mock", DEPRECATION_MESSAGE); return PARSER.apply(parser, null); } catch (IllegalArgumentException e) { @@ -85,4 +85,4 @@ protected boolean doEquals(MockDeprecatedQueryBuilder other) { protected int doHashCode() { return 0; } -} \ No newline at end of file +} diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/job/JobManager.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/job/JobManager.java index 30a8cafde6ed7..cec8ecb1f6a6a 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/job/JobManager.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/job/JobManager.java @@ -248,7 +248,7 @@ public void putJob(PutJobAction.Request request, AnalysisRegistry analysisRegist Job job = jobBuilder.build(new Date()); if (job.getDataDescription() != null && job.getDataDescription().getFormat() == DataDescription.DataFormat.DELIMITED) { - deprecationLogger.deprecatedAndMaybeLog("ml_create_job_delimited_data", + deprecationLogger.deprecate("ml_create_job_delimited_data", "Creating jobs with delimited data format is deprecated. Please use xcontent instead."); } diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/utils/DomainSplitFunction.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/utils/DomainSplitFunction.java index 452c1f5e9ed81..3be46392737a4 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/utils/DomainSplitFunction.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/utils/DomainSplitFunction.java @@ -157,7 +157,7 @@ private static String topPrivateDomain(String name, List parts, int publ public static List domainSplit(String host, Map params) { // NOTE: we don't check SpecialPermission because this will be called (indirectly) from scripts AccessController.doPrivileged((PrivilegedAction) () -> { - deprecationLogger.deprecatedAndMaybeLog("domainSplit", + deprecationLogger.deprecate("domainSplit", "Method [domainSplit] taking params is deprecated. Remove the params argument."); return null; }); diff --git a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/action/TransportPutRollupJobAction.java b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/action/TransportPutRollupJobAction.java index 59b8cdb8f9352..e2cf21064fa1c 100644 --- a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/action/TransportPutRollupJobAction.java +++ b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/action/TransportPutRollupJobAction.java @@ -134,9 +134,9 @@ static void checkForDeprecatedTZ(PutRollupJobAction.Request request) { String timeZone = request.getConfig().getGroupConfig().getDateHistogram().getTimeZone(); String modernTZ = DateUtils.DEPRECATED_LONG_TIMEZONES.get(timeZone); if (modernTZ != null) { - deprecationLogger.deprecatedAndMaybeLog("deprecated_timezone", + deprecationLogger.deprecate("deprecated_timezone", "Creating Rollup job [" + request.getConfig().getId() + "] with timezone [" - + timeZone + "], but [" + timeZone + "] has been deprecated by the IANA. Use [" + modernTZ +"] instead."); + + timeZone + "], but [" + timeZone + "] has been deprecated by the IANA. Use [" + modernTZ +"] instead."); } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java index e6fe002a6d2e9..460fa1147b4e2 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java @@ -622,25 +622,22 @@ private ApiKeyLoggingDeprecationHandler(DeprecationLogger logger, String apiKeyI @Override public void usedDeprecatedName(String parserName, Supplier location, String usedName, String modernName) { String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] "; - deprecationLogger.deprecatedAndMaybeLog("api_key_field", - "{}Deprecated field [{}] used in api key [{}], expected [{}] instead", - prefix, usedName, apiKeyId, modernName); + deprecationLogger.deprecate("api_key_field", + "{}Deprecated field [{}] used in api key [{}], expected [{}] instead", prefix, usedName, apiKeyId, modernName); } @Override public void usedDeprecatedField(String parserName, Supplier location, String usedName, String replacedWith) { String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] "; - deprecationLogger.deprecatedAndMaybeLog("api_key_field", - "{}Deprecated field [{}] used in api key [{}], replaced by [{}]", - prefix, usedName, apiKeyId, replacedWith); + deprecationLogger.deprecate("api_key_field", + "{}Deprecated field [{}] used in api key [{}], replaced by [{}]", prefix, usedName, apiKeyId, replacedWith); } @Override public void usedDeprecatedField(String parserName, Supplier location, String usedName) { String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] "; - deprecationLogger.deprecatedAndMaybeLog("api_key_field", - "{}Deprecated field [{}] used in api key [{}], which is unused and will be removed entirely", - prefix, usedName); + deprecationLogger.deprecate("api_key_field", + "{}Deprecated field [{}] used in api key [{}], which is unused and will be removed entirely", prefix, usedName, apiKeyId); } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealm.java index 36caee39d6091..9875662f1ee4f 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealm.java @@ -235,9 +235,9 @@ private void getUserInfo(final String username, ActionListener private void logDeprecatedUser(final User user){ Map metadata = user.metadata(); if (Boolean.TRUE.equals(metadata.get(MetadataUtils.DEPRECATED_METADATA_KEY))) { - deprecationLogger.deprecatedAndMaybeLog("deprecated_user-" + user.principal(), "The user [" + user.principal() + - "] is deprecated and will be removed in a future version of Elasticsearch. " + - metadata.get(MetadataUtils.DEPRECATED_REASON_METADATA_KEY)); + deprecationLogger.deprecate("deprecated_user-" + user.principal(), "The user [" + user.principal() + + "] is deprecated and will be removed in a future version of Elasticsearch. " + + metadata.get(MetadataUtils.DEPRECATED_REASON_METADATA_KEY)); } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java index 7aa1491e8ce93..94f5ee709b50a 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectorySessionFactory.java @@ -523,8 +523,7 @@ static class UpnADAuthenticator extends ADAuthenticator { super(config, timeout, ignoreReferralErrors, logger, groupsResolver, metadataResolver, domainDN, ActiveDirectorySessionFactorySettings.AD_UPN_USER_SEARCH_FILTER_SETTING, UPN_USER_FILTER, threadPool); if (userSearchFilter.contains("{0}")) { - new DeprecationLogger(logger).deprecatedAndMaybeLog("ldap_settings", - "The use of the account name variable {0} in the setting [" + new DeprecationLogger(logger).deprecate("ldap_settings", "The use of the account name variable {0} in the setting [" + RealmSettings.getFullSettingKey(config, ActiveDirectorySessionFactorySettings.AD_UPN_USER_SEARCH_FILTER_SETTING) + "] has been deprecated and will be removed in a future version!"); } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java index 31affff20dd24..aaef75f4e5f1c 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java @@ -159,12 +159,9 @@ protected static LDAPConnectionOptions connectionOptions(RealmConfig config, } else if (hostnameVerificationExists) { final String fullSettingKey = RealmSettings.getFullSettingKey(config, SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING); final String deprecationKey = "deprecated_setting_" + fullSettingKey.replace('.', '_'); - new DeprecationLogger(logger).deprecatedAndMaybeLog( - deprecationKey, - "the setting [{}] has been deprecated and " + "will be removed in a future version. use [{}] instead", - fullSettingKey, - RealmSettings.getFullSettingKey(config, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM) - ); + new DeprecationLogger(logger).deprecate(deprecationKey, + "the setting [{}] has been deprecated and will be removed in a future version. use [{}] instead", + fullSettingKey, RealmSettings.getFullSettingKey(config, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM)); if (config.getSetting(SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING)) { options.setSSLSocketVerifier(new HostNameSSLSocketVerifier(true)); } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java index 7875b33e7f862..4bb8f31f0bcbf 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java @@ -186,8 +186,8 @@ void logDeprecatedRoles(Set roleDescriptors) { .forEach(rd -> { String reason = Objects.toString( rd.getMetadata().get(MetadataUtils.DEPRECATED_REASON_METADATA_KEY), "Please check the documentation"); - deprecationLogger.deprecatedAndMaybeLog("deprecated_role-" + rd.getName(), "The role [" + rd.getName() + - "] is deprecated and will be removed in a future version of Elasticsearch. " + reason); + deprecationLogger.deprecate("deprecated_role-" + rd.getName(), "The role [" + rd.getName() + + "] is deprecated and will be removed in a future version of Elasticsearch. " + reason); }); } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/DeprecationRoleDescriptorConsumer.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/DeprecationRoleDescriptorConsumer.java index 04925984017ce..9e41c761ede44 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/DeprecationRoleDescriptorConsumer.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/DeprecationRoleDescriptorConsumer.java @@ -206,7 +206,7 @@ private void logDeprecatedPermission(RoleDescriptor roleDescriptor) { if (false == inferiorIndexNames.isEmpty()) { final String logMessage = String.format(Locale.ROOT, ROLE_PERMISSION_DEPRECATION_STANZA, roleDescriptor.getName(), aliasName, String.join(", ", inferiorIndexNames)); - deprecationLogger.deprecatedAndMaybeLog("index_permissions_on_alias", logMessage); + deprecationLogger.deprecate("index_permissions_on_alias", logMessage); } } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/DeprecationRoleDescriptorConsumerTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/DeprecationRoleDescriptorConsumerTests.java index 8fa4db6bcc09c..c41e70ac084b0 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/DeprecationRoleDescriptorConsumerTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/DeprecationRoleDescriptorConsumerTests.java @@ -296,7 +296,7 @@ private RoleDescriptor.IndicesPrivileges indexPrivileges(String priv, String... } private void verifyLogger(DeprecationLogger deprecationLogger, String roleName, String aliasName, String indexNames) { - verify(deprecationLogger).deprecatedAndMaybeLog("index_permissions_on_alias", + verify(deprecationLogger).deprecate("index_permissions_on_alias", "Role [" + roleName + "] contains index privileges covering the [" + aliasName + "] alias but which do not cover some of the indices that it points to [" + indexNames + "]. Granting privileges over an" + " alias and hence granting privileges over all the indices that the alias points to is deprecated and will be removed" diff --git a/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/mapper/SparseVectorFieldMapper.java b/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/mapper/SparseVectorFieldMapper.java index 400d2a388aa56..d8f67c3ee9112 100644 --- a/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/mapper/SparseVectorFieldMapper.java +++ b/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/mapper/SparseVectorFieldMapper.java @@ -77,7 +77,7 @@ public Mapper.Builder parse(String name, Map node, ParserCont if (parserContext.indexVersionCreated().onOrAfter(Version.V_8_0_0)) { throw new IllegalArgumentException(ERROR_MESSAGE); } else { - deprecationLogger.deprecatedAndMaybeLog("sparse_vector", ERROR_MESSAGE_7X); + deprecationLogger.deprecate("sparse_vector", ERROR_MESSAGE_7X); return new Builder(name); } } diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestWatcherStatsAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestWatcherStatsAction.java index 74f1d4a86f685..479300cddd179 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestWatcherStatsAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/rest/action/RestWatcherStatsAction.java @@ -53,8 +53,7 @@ protected RestChannelConsumer prepareRequest(final RestRequest restRequest, Node } if (metrics.contains("pending_watches")) { - deprecationLogger.deprecatedAndMaybeLog("pending_watches", - "The pending_watches parameter is deprecated, use queued_watches instead"); + deprecationLogger.deprecate("pending_watches", "The pending_watches parameter is deprecated, use queued_watches instead"); }