瀏覽代碼

Add compatible logging when parsing a compatible field (#69539)

A #68808 introduced a possibility to declare fields which will be only available to parsing when a compatible API was used.

This commit replaces deprecated log with compatible logging when a 'compatible only' field was used. Also includes a refactoring of LoggingDeprecationHandler method names

relates #51816
Przemyslaw Gomulka 4 年之前
父節點
當前提交
9ad9c781de
共有 21 個文件被更改,包括 271 次插入88 次删除
  1. 24 17
      libs/x-content/src/main/java/org/elasticsearch/common/ParseField.java
  2. 48 20
      libs/x-content/src/main/java/org/elasticsearch/common/xcontent/DeprecationHandler.java
  3. 88 2
      libs/x-content/src/test/java/org/elasticsearch/common/ParseFieldTests.java
  4. 0 1
      libs/x-content/src/test/java/org/elasticsearch/common/xcontent/ConstructingObjectParserTests.java
  5. 24 4
      qa/logging-config/src/test/java/org/elasticsearch/common/logging/JsonLoggerTests.java
  6. 1 1
      rest-api-spec/build.gradle
  7. 57 15
      server/src/main/java/org/elasticsearch/common/xcontent/LoggingDeprecationHandler.java
  8. 1 1
      test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
  9. 9 9
      x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/utils/LoggingDeprecationAccumulationHandler.java
  10. 2 2
      x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/utils/XContentObjectTransformerTests.java
  11. 1 1
      x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/ingest/InferenceProcessor.java
  12. 1 1
      x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/cat/RestCatDatafeedsAction.java
  13. 1 1
      x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/cat/RestCatJobsAction.java
  14. 1 1
      x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/datafeeds/RestGetDatafeedStatsAction.java
  15. 1 1
      x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/datafeeds/RestGetDatafeedsAction.java
  16. 1 1
      x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/datafeeds/RestStopDatafeedAction.java
  17. 1 1
      x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestCloseJobAction.java
  18. 1 1
      x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestGetJobStatsAction.java
  19. 1 1
      x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestGetJobsAction.java
  20. 1 1
      x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/results/RestGetOverallBucketsAction.java
  21. 7 6
      x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java

+ 24 - 17
libs/x-content/src/main/java/org/elasticsearch/common/ParseField.java

@@ -25,15 +25,19 @@ public class ParseField {
     private final String name;
     private final String[] deprecatedNames;
     private final Function<RestApiVersion, Boolean> forRestApiVersion;
-    private String allReplacedWith = null;
+    private final String allReplacedWith;
+    private boolean fullyDeprecated;
+
     private final String[] allNames;
-    private boolean fullyDeprecated = false;
 
     private static final String[] EMPTY = new String[0];
 
 
-    private ParseField(String name, Function<RestApiVersion, Boolean> forRestApiVersion, String[] deprecatedNames) {
+    private ParseField(String name, Function<RestApiVersion, Boolean> forRestApiVersion, String[] deprecatedNames,
+                       boolean fullyDeprecated, String allReplacedWith) {
         this.name = name;
+        this.fullyDeprecated = fullyDeprecated;
+        this.allReplacedWith = allReplacedWith;
         if (deprecatedNames == null || deprecatedNames.length == 0) {
             this.deprecatedNames = EMPTY;
         } else {
@@ -57,7 +61,8 @@ public class ParseField {
      *                        accepted when strict matching is used.
      */
     public ParseField(String name, String... deprecatedNames) {
-        this(name, RestApiVersion.onOrAfter(RestApiVersion.minimumSupported()) ,deprecatedNames);
+        this(name, RestApiVersion.onOrAfter(RestApiVersion.minimumSupported()) ,deprecatedNames,
+            false, null);
     }
 
     /**
@@ -83,20 +88,21 @@ public class ParseField {
      *         but with the specified deprecated names
      */
     public ParseField withDeprecation(String... deprecatedNames) {
-        return new ParseField(this.name, deprecatedNames);
+        return new ParseField(this.name, this.forRestApiVersion, deprecatedNames, this.fullyDeprecated, this.allReplacedWith);
     }
 
 
     /**
      * Creates a new field with current name and deprecatedNames, but overrides forRestApiVersion
-     * @param forRestApiVersion - a boolean function indicating if a field is for the given RestApiVersion
+     * @param forRestApiVersion - a boolean function indicating for what version a deprecated name is available
      */
     public ParseField forRestApiVersion(Function<RestApiVersion, Boolean> forRestApiVersion) {
-        return new ParseField(this.name, forRestApiVersion, this.deprecatedNames);
+        return new ParseField(this.name, forRestApiVersion, this.deprecatedNames,
+            this.fullyDeprecated, this.allReplacedWith);
     }
 
     /**
-     * @return a function indicating for which RestApiVersion a field is declared for
+     * @return a function indicating for which RestApiVersion a deprecated name is declared for
      */
     public Function<RestApiVersion, Boolean> getForRestApiVersion() {
         return forRestApiVersion;
@@ -107,18 +113,16 @@ public class ParseField {
      * with {@code allReplacedWith}.
      */
     public ParseField withAllDeprecated(String allReplacedWith) {
-        ParseField parseField = this.withDeprecation(getAllNamesIncludedDeprecated());
-        parseField.allReplacedWith = allReplacedWith;
-        return parseField;
+        return new ParseField(this.name, this.forRestApiVersion, getAllNamesIncludedDeprecated(),
+            this.fullyDeprecated, allReplacedWith);
     }
 
     /**
      * Return a new ParseField where all field names are deprecated with no replacement
      */
     public ParseField withAllDeprecated() {
-        ParseField parseField = this.withDeprecation(getAllNamesIncludedDeprecated());
-        parseField.fullyDeprecated = true;
-        return parseField;
+        return new ParseField(this.name, this.forRestApiVersion, getAllNamesIncludedDeprecated(),
+            true, this.allReplacedWith);
     }
 
     /**
@@ -152,17 +156,20 @@ public class ParseField {
         if (fullyDeprecated == false && allReplacedWith == null && fieldName.equals(name)) {
             return true;
         }
+        boolean isCompatibleDeprecation = RestApiVersion.minimumSupported().matches(forRestApiVersion) &&
+            RestApiVersion.current().matches(forRestApiVersion) == false;
+
         // Now try to match against one of the deprecated names. Note that if
         // the parse field is entirely deprecated (allReplacedWith != null) all
         // fields will be in the deprecatedNames array
         for (String depName : deprecatedNames) {
             if (fieldName.equals(depName)) {
                 if (fullyDeprecated) {
-                    deprecationHandler.usedDeprecatedField(parserName, location, fieldName);
+                    deprecationHandler.logRemovedField(parserName, location, fieldName, isCompatibleDeprecation);
                 } else if (allReplacedWith == null) {
-                    deprecationHandler.usedDeprecatedName(parserName, location, fieldName, name);
+                    deprecationHandler.logRenamedField(parserName, location, fieldName, name, isCompatibleDeprecation);
                 } else {
-                    deprecationHandler.usedDeprecatedField(parserName, location, fieldName, allReplacedWith);
+                    deprecationHandler.logReplacedField(parserName, location, fieldName, allReplacedWith, isCompatibleDeprecation);
                 }
                 return true;
             }

+ 48 - 20
libs/x-content/src/main/java/org/elasticsearch/common/xcontent/DeprecationHandler.java

@@ -23,34 +23,34 @@ public interface DeprecationHandler {
      */
     DeprecationHandler THROW_UNSUPPORTED_OPERATION = new DeprecationHandler() {
         @Override
-        public void usedDeprecatedField(String parserName, Supplier<XContentLocation> location, String usedName, String replacedWith) {
+        public void logReplacedField(String parserName, Supplier<XContentLocation> location, String oldName, String replacedName) {
             if (parserName != null) {
                 throw new UnsupportedOperationException("deprecated fields not supported in [" + parserName + "] but got ["
-                    + usedName + "] at [" + location.get() + "] which is a deprecated name for [" + replacedWith + "]");
+                    + oldName + "] at [" + location.get() + "] which is a deprecated name for [" + replacedName + "]");
             } else {
                 throw new UnsupportedOperationException("deprecated fields not supported here but got ["
-                    + usedName + "] which is a deprecated name for [" + replacedWith + "]");
+                    + oldName + "] which is a deprecated name for [" + replacedName + "]");
             }
         }
         @Override
-        public void usedDeprecatedName(String parserName, Supplier<XContentLocation> location, String usedName, String modernName) {
+        public void logRenamedField(String parserName, Supplier<XContentLocation> location, String oldName, String currentName) {
             if (parserName != null) {
                 throw new UnsupportedOperationException("deprecated fields not supported in [" + parserName + "] but got ["
-                    + usedName + "] at [" + location.get() + "] which has been replaced with [" + modernName + "]");
+                    + oldName + "] at [" + location.get() + "] which has been replaced with [" + currentName + "]");
             } else {
                 throw new UnsupportedOperationException("deprecated fields not supported here but got ["
-                    + usedName + "] which has been replaced with [" + modernName + "]");
+                    + oldName + "] which has been replaced with [" + currentName + "]");
             }
         }
 
         @Override
-        public void usedDeprecatedField(String parserName, Supplier<XContentLocation> location, String usedName) {
+        public void logRemovedField(String parserName, Supplier<XContentLocation> location, String removedName) {
             if (parserName != null) {
                 throw new UnsupportedOperationException("deprecated fields not supported in [" + parserName + "] but got ["
-                    + usedName + "] at [" + location.get() + "] which has been deprecated entirely");
+                    + removedName + "] at [" + location.get() + "] which has been deprecated entirely");
             } else {
                 throw new UnsupportedOperationException("deprecated fields not supported here but got ["
-                    + usedName + "] which has been deprecated entirely");
+                    + removedName + "] which has been deprecated entirely");
             }
         }
     };
@@ -60,41 +60,69 @@ public interface DeprecationHandler {
      */
     DeprecationHandler IGNORE_DEPRECATIONS = new DeprecationHandler() {
         @Override
-        public void usedDeprecatedName(String parserName, Supplier<XContentLocation> location, String usedName, String modernName) {
+        public void logRenamedField(String parserName, Supplier<XContentLocation> location, String oldName, String currentName) {
 
         }
 
         @Override
-        public void usedDeprecatedField(String parserName, Supplier<XContentLocation> location, String usedName, String replacedWith) {
+        public void logReplacedField(String parserName, Supplier<XContentLocation> location, String oldName, String replacedName) {
 
         }
 
         @Override
-        public void usedDeprecatedField(String parserName, Supplier<XContentLocation> location, String usedName) {
+        public void logRemovedField(String parserName, Supplier<XContentLocation> location, String removedName) {
 
         }
     };
 
     /**
      * Called when the provided field name matches a deprecated name for the field.
-     * @param usedName the provided field name
-     * @param modernName the modern name for the field
+     * @param oldName the provided field name
+     * @param currentName the modern name for the field
      */
-    void usedDeprecatedName(String parserName, Supplier<XContentLocation> location, String usedName, String modernName);
+    void logRenamedField(String parserName, Supplier<XContentLocation> location, String oldName, String currentName);
 
     /**
      * Called when the provided field name matches the current field but the entire
      * field has been marked as deprecated and another field should be used
-     * @param usedName the provided field name
-     * @param replacedWith the name of the field that replaced this field
+     * @param oldName the provided field name
+     * @param replacedName the name of the field that replaced this field
      */
-    void usedDeprecatedField(String parserName, Supplier<XContentLocation> location, String usedName, String replacedWith);
+    void logReplacedField(String parserName, Supplier<XContentLocation> location, String oldName, String replacedName);
 
     /**
      * Called when the provided field name matches the current field but the entire
      * field has been marked as deprecated with no replacement
-     * @param usedName the provided field name
+     * Emits a compatible api warning instead of deprecation warning when isCompatibleDeprecation is true
+     * @param removedName the provided field name
      */
-    void usedDeprecatedField(String parserName, Supplier<XContentLocation> location, String usedName);
+    void logRemovedField(String parserName, Supplier<XContentLocation> location, String removedName);
+
+    /**
+     * @see DeprecationHandler#logRenamedField(String, Supplier, String, String)
+     * Emits a compatible api warning instead of deprecation warning when isCompatibleDeprecation is true
+     */
+    default void logRenamedField(String parserName, Supplier<XContentLocation> location, String oldName, String currentName,
+                                 boolean isCompatibleDeprecation) {
+        logRenamedField(parserName, location, oldName, currentName);
+    }
+
+    /**
+     * @see DeprecationHandler#logReplacedField(String, Supplier, String, String)
+     * Emits a compatible api warning instead of deprecation warning when isCompatibleDeprecation is true
+     */
+    default void logReplacedField(String parserName, Supplier<XContentLocation> location, String oldName, String replacedName,
+                                  boolean isCompatibleDeprecation) {
+        logReplacedField(parserName, location, oldName, replacedName);
+    }
+
+    /**
+     * @see DeprecationHandler#logRemovedField(String, Supplier, String)
+     * Emits a compatible api warning instead of deprecation warning when isCompatibleDeprecation is true
+     */
+    default void logRemovedField(String parserName, Supplier<XContentLocation> location, String removedName,
+                                 boolean isCompatibleDeprecation) {
+        logRemovedField(parserName, location, removedName);
+    }
 
 }

+ 88 - 2
libs/x-content/src/test/java/org/elasticsearch/common/ParseFieldTests.java

@@ -7,9 +7,13 @@
  */
 package org.elasticsearch.common;
 
+import org.elasticsearch.common.xcontent.DeprecationHandler;
 import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
+import org.elasticsearch.common.xcontent.XContentLocation;
 import org.elasticsearch.test.ESTestCase;
 
+import java.util.function.Supplier;
+
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.sameInstance;
@@ -60,8 +64,6 @@ public class ParseFieldTests extends ESTestCase {
         assertWarnings("Deprecated field [old_dep] used, this field is unused and will be removed entirely");
         assertTrue(field.match("new_dep", LoggingDeprecationHandler.INSTANCE));
         assertWarnings("Deprecated field [new_dep] used, this field is unused and will be removed entirely");
-
-
     }
 
     public void testGetAllNamesIncludedDeprecated() {
@@ -71,4 +73,88 @@ public class ParseFieldTests extends ESTestCase {
         parseField = new ParseField("more_like_this", "mlt");
         assertThat(parseField.getAllNamesIncludedDeprecated(), arrayContainingInAnyOrder("more_like_this", "mlt"));
     }
+
+    class TestDeprecationHandler implements DeprecationHandler {
+
+        public boolean compatibleWarningsUsed = false;
+
+        @Override
+        public void logRenamedField(String parserName, Supplier<XContentLocation> location, String oldName, String currentName) {
+        }
+
+        @Override
+        public void logReplacedField(String parserName, Supplier<XContentLocation> location, String oldName, String replacedName) {
+        }
+
+        @Override
+        public void logRemovedField(String parserName, Supplier<XContentLocation> location, String removedName) {
+        }
+
+        @Override
+        public void logRenamedField(String parserName, Supplier<XContentLocation> location, String oldName, String currentName,
+                                    boolean isCompatibleDeprecation) {
+            this.compatibleWarningsUsed = isCompatibleDeprecation;
+        }
+
+        @Override
+        public void logReplacedField(String parserName, Supplier<XContentLocation> location, String oldName, String replacedName,
+                                     boolean isCompatibleDeprecation) {
+            this.compatibleWarningsUsed = isCompatibleDeprecation;
+
+        }
+
+        @Override
+        public void logRemovedField(String parserName, Supplier<XContentLocation> location, String removedName,
+                                    boolean isCompatibleDeprecation) {
+            this.compatibleWarningsUsed = isCompatibleDeprecation;
+        }
+    }
+
+    public void testCompatibleLoggerIsUsed() {
+        {
+            // a field deprecated in previous version and now available under old name only in compatible api
+            // emitting compatible logs
+            ParseField field = new ParseField("new_name", "old_name")
+                .forRestApiVersion(RestApiVersion.equalTo(RestApiVersion.minimumSupported()));
+
+            TestDeprecationHandler  testDeprecationHandler = new TestDeprecationHandler();
+
+            assertTrue(field.match("old_name", testDeprecationHandler));
+            assertThat(testDeprecationHandler.compatibleWarningsUsed , is(true));
+        }
+
+        {
+            //a regular newly deprecated field. Emitting deprecation logs instead of compatible logs
+            ParseField field = new ParseField("new_name", "old_name");
+
+            TestDeprecationHandler  testDeprecationHandler = new TestDeprecationHandler();
+
+            assertTrue(field.match("old_name", testDeprecationHandler));
+            assertThat(testDeprecationHandler.compatibleWarningsUsed , is(false));
+        }
+
+    }
+
+    public void testCompatibleWarnings() {
+        ParseField field = new ParseField("new_name", "old_name")
+            .forRestApiVersion(RestApiVersion.equalTo(RestApiVersion.minimumSupported()));
+
+        assertTrue(field.match("new_name", LoggingDeprecationHandler.INSTANCE));
+        ensureNoWarnings();
+        assertTrue(field.match("old_name", LoggingDeprecationHandler.INSTANCE));
+        assertWarnings("Deprecated field [old_name] used, expected [new_name] instead");
+
+        ParseField allDepField = new ParseField("dep", "old_name")
+            .withAllDeprecated()
+            .forRestApiVersion(RestApiVersion.equalTo(RestApiVersion.minimumSupported()));
+
+        assertTrue(allDepField.match("dep", LoggingDeprecationHandler.INSTANCE));
+        assertWarnings("Deprecated field [dep] used, this field is unused and will be removed entirely");
+        assertTrue(allDepField.match("old_name", LoggingDeprecationHandler.INSTANCE));
+        assertWarnings("Deprecated field [old_name] used, this field is unused and will be removed entirely");
+
+        ParseField regularField = new ParseField("new_name");
+        assertTrue(regularField.match("new_name", LoggingDeprecationHandler.INSTANCE));
+        ensureNoWarnings();
+    }
 }

+ 0 - 1
libs/x-content/src/test/java/org/elasticsearch/common/xcontent/ConstructingObjectParserTests.java

@@ -627,7 +627,6 @@ public class ConstructingObjectParserTests extends ESTestCase {
             assertEquals(1, o.intField);
             assertWarnings(false, "[struct_with_compatible_fields][1:14] " +
                 "Deprecated field [old_name] used, expected [new_name] instead");
-
         }
     }
 

+ 24 - 4
qa/logging-config/src/test/java/org/elasticsearch/common/logging/JsonLoggerTests.java

@@ -16,6 +16,7 @@ import org.apache.logging.log4j.core.config.Configurator;
 import org.elasticsearch.cli.UserException;
 import org.elasticsearch.common.CheckedConsumer;
 import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.RestApiVersion;
 import org.elasticsearch.common.io.PathUtils;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.util.concurrent.ThreadContext;
@@ -164,8 +165,7 @@ public class JsonLoggerTests extends ESTestCase {
             assertWarnings("deprecated message1", "compatible API message");
         });
     }
-
-    public void testParseFieldEmittingLogs() throws Exception {
+    public void testParseFieldEmittingDeprecatedLogs() throws Exception {
         withThreadContext(threadContext -> {
             threadContext.putHeader(Task.X_OPAQUE_ID, "someId");
 
@@ -175,6 +175,10 @@ public class JsonLoggerTests extends ESTestCase {
             ParseField deprecatedField2 = new ParseField("new_name", "deprecated_name2");
             assertTrue(deprecatedField2.match("deprecated_name2", LoggingDeprecationHandler.INSTANCE));
 
+            ParseField compatibleField = new ParseField("new_name", "compatible_deprecated_name")
+                .forRestApiVersion(RestApiVersion.equalTo(RestApiVersion.minimumSupported()));
+            assertTrue(compatibleField.match("compatible_deprecated_name", LoggingDeprecationHandler.INSTANCE));
+
             final Path path = PathUtils.get(
                 System.getProperty("es.logs.base_path"),
                 System.getProperty("es.logs.cluster_name") + "_deprecated.json"
@@ -201,7 +205,7 @@ public class JsonLoggerTests extends ESTestCase {
                             hasEntry(DeprecatedMessage.X_OPAQUE_ID_FIELD_NAME, "someId"),
                             hasEntry("elasticsearch.event.category", "api")
                         ),
-                        // deprecation log for field deprecated_name2
+                        // deprecation log for field deprecated_name2 (note it is not being throttled)
                         allOf(
                             hasEntry("log.level", "DEPRECATION"),
                             hasEntry("event.dataset", "elasticsearch.deprecation"),
@@ -215,13 +219,29 @@ public class JsonLoggerTests extends ESTestCase {
                             hasEntry(DeprecatedMessage.KEY_FIELD_NAME, "deprecated_field_deprecated_name2"),
                             hasEntry(DeprecatedMessage.X_OPAQUE_ID_FIELD_NAME, "someId"),
                             hasEntry("elasticsearch.event.category", "api")
+                        ),
+                        //compatible  log line
+                        allOf(
+                            hasEntry("log.level", "DEPRECATION"),
+                            hasEntry("event.dataset", "elasticsearch.deprecation"),
+                            hasEntry("data_stream.dataset", "elasticsearch.deprecation"),
+                            hasEntry("data_stream.type", "logs"),
+                            hasEntry("log.logger", "org.elasticsearch.deprecation.common.ParseField"),
+                            hasEntry("ecs.version", DeprecatedMessage.ECS_VERSION),
+                            hasEntry("elasticsearch.cluster.name", "elasticsearch"),
+                            hasEntry("elasticsearch.node.name", "sample-name"),
+                            hasEntry("message", "Deprecated field [compatible_deprecated_name] used, expected [new_name] instead"),
+                            hasEntry(DeprecatedMessage.KEY_FIELD_NAME, "deprecated_field_compatible_deprecated_name"),
+                            hasEntry(DeprecatedMessage.X_OPAQUE_ID_FIELD_NAME, "someId"),
+                            hasEntry("elasticsearch.event.category", "compatible_api")
                         )
                     )
                 );
             }
 
             assertWarnings("Deprecated field [deprecated_name] used, expected [new_name] instead",
-                "Deprecated field [deprecated_name2] used, expected [new_name] instead");
+                "Deprecated field [deprecated_name2] used, expected [new_name] instead",
+                "Deprecated field [compatible_deprecated_name] used, expected [new_name] instead");
         });
     }
 

+ 1 - 1
rest-api-spec/build.gradle

@@ -338,6 +338,7 @@ tasks.named("yamlRestCompatTest").configure {
     'search/110_field_collapsing/field collapsing, inner_hits and maxConcurrentGroupRequests',
     'search/110_field_collapsing/field collapsing, inner_hits and seq_no',
     'search/110_field_collapsing/field collapsing, inner_hits and version',
+    'search/110_field_collapsing/field collapsing and inner_hits',
     'search/150_rewrite_on_coordinator/Ensure that we fetch the document only once',
     'search/160_exists_query/Test exists query on _type field',
     'search/171_terms_query_with_types/Terms Query with No.of terms exceeding index.max_terms_count should FAIL',
@@ -347,7 +348,6 @@ tasks.named("yamlRestCompatTest").configure {
     'search/40_indices_boost/Indices boost using object',
     'search/70_response_filtering/Search with response filtering',
     'search/90_search_after/search with search_after parameter',
-    'search/110_field_collapsing/field collapsing and inner_hits',
     'search_shards/10_basic/Search shards aliases with and without filters',
     'snapshot.get/10_basic/Get missing snapshot info succeeds when ignore_unavailable is true',
     'snapshot.get/10_basic/Get missing snapshot info throws an exception',

+ 57 - 15
server/src/main/java/org/elasticsearch/common/xcontent/LoggingDeprecationHandler.java

@@ -9,6 +9,7 @@
 package org.elasticsearch.common.xcontent;
 
 import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.TriConsumer;
 import org.elasticsearch.common.logging.DeprecationCategory;
 import org.elasticsearch.common.logging.DeprecationLogger;
 
@@ -24,10 +25,9 @@ import java.util.function.Supplier;
  * though the user sent them.
  */
 public class LoggingDeprecationHandler implements DeprecationHandler {
-    public static final LoggingDeprecationHandler INSTANCE = new LoggingDeprecationHandler();
     /**
      * The logger to which to send deprecation messages.
-     *
+     * <p>
      * This uses ParseField's logger because that is the logger that
      * we have been using for many releases for deprecated fields.
      * Changing that will require some research to make super duper
@@ -35,28 +35,70 @@ public class LoggingDeprecationHandler implements DeprecationHandler {
      */
     private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(ParseField.class);
 
+    public static final LoggingDeprecationHandler INSTANCE = new LoggingDeprecationHandler();
+
+    private TriConsumer<String, Object[], String> deprecationLoggerFunction = (message, params, field_name) ->
+        deprecationLogger.deprecate(DeprecationCategory.API, "deprecated_field_" + field_name, message, params);
+
+    private TriConsumer<String, Object[], String> compatibleLoggerFunction = (message, params, field_name) ->
+        deprecationLogger.compatibleApiWarning("deprecated_field_" + field_name, message, params);
+
     private LoggingDeprecationHandler() {
-        // Singleton
+        // one instance only
     }
 
     @Override
-    public void usedDeprecatedName(String parserName, Supplier<XContentLocation> location, String usedName, String modernName) {
-        String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] ";
-        deprecationLogger.deprecate(DeprecationCategory.API, "deprecated_field_" + usedName,
-            "{}Deprecated field [{}] used, expected [{}] instead", prefix, usedName, modernName);
+    public void logRenamedField(String parserName, Supplier<XContentLocation> location, String oldName, String currentName) {
+        logRenamedField(parserName, location, oldName, currentName, false);
     }
 
     @Override
-    public void usedDeprecatedField(String parserName, Supplier<XContentLocation> location, String usedName, String replacedWith) {
-        String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] ";
-        deprecationLogger.deprecate(DeprecationCategory.API, "deprecated_field_" + usedName,
-            "{}Deprecated field [{}] used, replaced by [{}]", prefix, usedName, replacedWith);
+    public void logReplacedField(String parserName, Supplier<XContentLocation> location, String oldName, String replacedName) {
+        logReplacedField(parserName, location, oldName, replacedName, false);
     }
 
     @Override
-    public void usedDeprecatedField(String parserName, Supplier<XContentLocation> location, String usedName) {
-        String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] ";
-        deprecationLogger.deprecate(DeprecationCategory.API, "deprecated_field_" + usedName,
-            "{}Deprecated field [{}] used, this field is unused and will be removed entirely", prefix, usedName);
+    public void logRemovedField(String parserName, Supplier<XContentLocation> location, String removedName) {
+        logRemovedField(parserName, location, removedName, false);
+    }
+
+    @Override
+    public void logRenamedField(String parserName, Supplier<XContentLocation> location, String oldName, String currentName,
+                                boolean isCompatibleDeprecation) {
+        String prefix = parserLocation(parserName, location);
+        TriConsumer<String, Object[], String> loggingFunction = getLoggingFunction(isCompatibleDeprecation);
+        loggingFunction.apply("{}Deprecated field [{}] used, expected [{}] instead",
+            new Object[]{prefix, oldName, currentName}, oldName);
+    }
+
+    @Override
+    public void logReplacedField(String parserName, Supplier<XContentLocation> location, String oldName, String replacedName,
+                                 boolean isCompatibleDeprecation) {
+        String prefix = parserLocation(parserName, location);
+        TriConsumer<String, Object[], String> loggingFunction = getLoggingFunction(isCompatibleDeprecation);
+        loggingFunction.apply("{}Deprecated field [{}] used, replaced by [{}]",
+            new Object[]{prefix, oldName, replacedName}, oldName);
+    }
+
+    @Override
+    public void logRemovedField(String parserName, Supplier<XContentLocation> location, String removedName,
+                                boolean isCompatibleDeprecation) {
+        String prefix = parserLocation(parserName, location);
+        TriConsumer<String, Object[], String> loggingFunction = getLoggingFunction(isCompatibleDeprecation);
+        loggingFunction.apply("{}Deprecated field [{}] used, this field is unused and will be removed entirely",
+            new Object[]{prefix, removedName}, removedName);
+
+    }
+
+    private String parserLocation(String parserName, Supplier<XContentLocation> location) {
+        return parserName == null ? "" : "[" + parserName + "][" + location.get() + "] ";
+    }
+
+    private TriConsumer<String, Object[], String> getLoggingFunction(boolean isCompatibleDeprecation) {
+        if (isCompatibleDeprecation) {
+            return compatibleLoggerFunction;
+        } else {
+            return deprecationLoggerFunction;
+        }
     }
 }

+ 1 - 1
test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java

@@ -402,7 +402,7 @@ public abstract class ESTestCase extends LuceneTestCase {
         return "[" + name.substring(start + 1, end) + "] ";
     }
 
-    private void ensureNoWarnings() {
+    public void ensureNoWarnings() {
         //Check that there are no unaccounted warning headers. These should be checked with {@link #assertWarnings(String...)} in the
         //appropriate test
         try {

+ 9 - 9
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/utils/LoggingDeprecationAccumulationHandler.java

@@ -29,27 +29,27 @@ public class LoggingDeprecationAccumulationHandler implements DeprecationHandler
     private final List<String> deprecations = new ArrayList<>();
 
     @Override
-    public void usedDeprecatedName(String parserName, Supplier<XContentLocation> location, String usedName, String modernName) {
-        LoggingDeprecationHandler.INSTANCE.usedDeprecatedName(parserName, location, usedName, modernName);
+    public void logRenamedField(String parserName, Supplier<XContentLocation> location, String oldName, String currentName) {
+        LoggingDeprecationHandler.INSTANCE.logRenamedField(parserName, location, oldName, currentName);
         String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] ";
         deprecations.add(LoggerMessageFormat.format("{}Deprecated field [{}] used, expected [{}] instead",
-            new Object[]{prefix, usedName, modernName}));
+            new Object[]{prefix, oldName, currentName}));
     }
 
     @Override
-    public void usedDeprecatedField(String parserName, Supplier<XContentLocation> location, String usedName, String replacedWith) {
-        LoggingDeprecationHandler.INSTANCE.usedDeprecatedField(parserName, location, usedName, replacedWith);
+    public void logReplacedField(String parserName, Supplier<XContentLocation> location, String oldName, String replacedName) {
+        LoggingDeprecationHandler.INSTANCE.logReplacedField(parserName, location, oldName, replacedName);
         String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] ";
         deprecations.add(LoggerMessageFormat.format("{}Deprecated field [{}] used, replaced by [{}]",
-            new Object[]{prefix, usedName, replacedWith}));
+            new Object[]{prefix, oldName, replacedName}));
     }
 
     @Override
-    public void usedDeprecatedField(String parserName, Supplier<XContentLocation> location, String usedName) {
-        LoggingDeprecationHandler.INSTANCE.usedDeprecatedField(parserName, location, usedName);
+    public void logRemovedField(String parserName, Supplier<XContentLocation> location, String removedName) {
+        LoggingDeprecationHandler.INSTANCE.logRemovedField(parserName, location, removedName);
         String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] ";
         deprecations.add(LoggerMessageFormat.format("{}Deprecated field [{}] used, unused and will be removed entirely",
-            new Object[]{prefix, usedName}));
+            new Object[]{prefix, removedName}));
     }
 
     /**

+ 2 - 2
x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/utils/XContentObjectTransformerTests.java

@@ -129,8 +129,8 @@ public class XContentObjectTransformerTests extends ESTestCase {
     public void testDeprecationWarnings() throws IOException {
         XContentObjectTransformer<QueryBuilder> queryBuilderTransformer = new XContentObjectTransformer<>(NamedXContentRegistry.EMPTY,
             (p)-> {
-            p.getDeprecationHandler().usedDeprecatedField(null, null, "oldField", "newField");
-            p.getDeprecationHandler().usedDeprecatedName(null, null, "oldName", "modernName");
+            p.getDeprecationHandler().logReplacedField(null, null, "oldField", "newField");
+            p.getDeprecationHandler().logRenamedField(null, null, "oldName", "modernName");
             return new BoolQueryBuilder();
             });
         List<String> deprecations = new ArrayList<>();

+ 1 - 1
x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/ingest/InferenceProcessor.java

@@ -299,7 +299,7 @@ public class InferenceProcessor extends AbstractProcessor {
                 fieldMap = ConfigurationUtils.readOptionalMap(TYPE, tag, config, FIELD_MAPPINGS);
                 //TODO Remove in 8.x
                 if (fieldMap != null) {
-                    LoggingDeprecationHandler.INSTANCE.usedDeprecatedName(null, () -> null, FIELD_MAPPINGS, FIELD_MAP);
+                    LoggingDeprecationHandler.INSTANCE.logRenamedField(null, () -> null, FIELD_MAPPINGS, FIELD_MAP);
                 }
             }
             if (fieldMap == null) {

+ 1 - 1
x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/cat/RestCatDatafeedsAction.java

@@ -50,7 +50,7 @@ public class RestCatDatafeedsAction extends AbstractCatAction {
         }
         Request request = new Request(datafeedId);
         if (restRequest.hasParam(Request.ALLOW_NO_DATAFEEDS)) {
-            LoggingDeprecationHandler.INSTANCE.usedDeprecatedName(null, () -> null, Request.ALLOW_NO_DATAFEEDS, Request.ALLOW_NO_MATCH);
+            LoggingDeprecationHandler.INSTANCE.logRenamedField(null, () -> null, Request.ALLOW_NO_DATAFEEDS, Request.ALLOW_NO_MATCH);
         }
         request.setAllowNoMatch(
             restRequest.paramAsBoolean(

+ 1 - 1
x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/cat/RestCatJobsAction.java

@@ -55,7 +55,7 @@ public class RestCatJobsAction extends AbstractCatAction {
         }
         Request request = new Request(jobId);
         if (restRequest.hasParam(Request.ALLOW_NO_JOBS)) {
-            LoggingDeprecationHandler.INSTANCE.usedDeprecatedName(null, () -> null, Request.ALLOW_NO_JOBS, Request.ALLOW_NO_MATCH);
+            LoggingDeprecationHandler.INSTANCE.logRenamedField(null, () -> null, Request.ALLOW_NO_JOBS, Request.ALLOW_NO_MATCH);
         }
         request.setAllowNoMatch(
             restRequest.paramAsBoolean(

+ 1 - 1
x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/datafeeds/RestGetDatafeedStatsAction.java

@@ -45,7 +45,7 @@ public class RestGetDatafeedStatsAction extends BaseRestHandler {
         }
         Request request = new Request(datafeedId);
         if (restRequest.hasParam(Request.ALLOW_NO_DATAFEEDS)) {
-            LoggingDeprecationHandler.INSTANCE.usedDeprecatedName(null, () -> null, Request.ALLOW_NO_DATAFEEDS, Request.ALLOW_NO_MATCH);
+            LoggingDeprecationHandler.INSTANCE.logRenamedField(null, () -> null, Request.ALLOW_NO_DATAFEEDS, Request.ALLOW_NO_MATCH);
         }
         request.setAllowNoMatch(
             restRequest.paramAsBoolean(

+ 1 - 1
x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/datafeeds/RestGetDatafeedsAction.java

@@ -47,7 +47,7 @@ public class RestGetDatafeedsAction extends BaseRestHandler {
         }
         Request request = new Request(datafeedId);
         if (restRequest.hasParam(Request.ALLOW_NO_DATAFEEDS)) {
-            LoggingDeprecationHandler.INSTANCE.usedDeprecatedName(null, () -> null, Request.ALLOW_NO_DATAFEEDS, Request.ALLOW_NO_MATCH);
+            LoggingDeprecationHandler.INSTANCE.logRenamedField(null, () -> null, Request.ALLOW_NO_DATAFEEDS, Request.ALLOW_NO_MATCH);
         }
         request.setAllowNoMatch(
             restRequest.paramAsBoolean(

+ 1 - 1
x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/datafeeds/RestStopDatafeedAction.java

@@ -60,7 +60,7 @@ public class RestStopDatafeedAction extends BaseRestHandler {
                 request.setForce(restRequest.paramAsBoolean(Request.FORCE.getPreferredName(), request.isForce()));
             }
             if (restRequest.hasParam(Request.ALLOW_NO_DATAFEEDS)) {
-                LoggingDeprecationHandler.INSTANCE.usedDeprecatedName(
+                LoggingDeprecationHandler.INSTANCE.logRenamedField(
                     null, () -> null, Request.ALLOW_NO_DATAFEEDS, Request.ALLOW_NO_MATCH.getPreferredName());
             }
             request.setAllowNoMatch(

+ 1 - 1
x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestCloseJobAction.java

@@ -52,7 +52,7 @@ public class RestCloseJobAction extends BaseRestHandler {
                 request.setForce(restRequest.paramAsBoolean(Request.FORCE.getPreferredName(), request.isForce()));
             }
             if (restRequest.hasParam(Request.ALLOW_NO_JOBS)) {
-                LoggingDeprecationHandler.INSTANCE.usedDeprecatedName(
+                LoggingDeprecationHandler.INSTANCE.logRenamedField(
                     null, () -> null, Request.ALLOW_NO_JOBS, Request.ALLOW_NO_MATCH.getPreferredName());
             }
             request.setAllowNoMatch(

+ 1 - 1
x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestGetJobStatsAction.java

@@ -46,7 +46,7 @@ public class RestGetJobStatsAction extends BaseRestHandler {
         }
         Request request = new Request(jobId);
         if (restRequest.hasParam(Request.ALLOW_NO_JOBS)) {
-            LoggingDeprecationHandler.INSTANCE.usedDeprecatedName(null, () -> null, Request.ALLOW_NO_JOBS, Request.ALLOW_NO_MATCH);
+            LoggingDeprecationHandler.INSTANCE.logRenamedField(null, () -> null, Request.ALLOW_NO_JOBS, Request.ALLOW_NO_MATCH);
         }
         request.setAllowNoMatch(
             restRequest.paramAsBoolean(

+ 1 - 1
x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/job/RestGetJobsAction.java

@@ -49,7 +49,7 @@ public class RestGetJobsAction extends BaseRestHandler {
         }
         Request request = new Request(jobId);
         if (restRequest.hasParam(Request.ALLOW_NO_JOBS)) {
-            LoggingDeprecationHandler.INSTANCE.usedDeprecatedName(null, () -> null, Request.ALLOW_NO_JOBS, Request.ALLOW_NO_MATCH);
+            LoggingDeprecationHandler.INSTANCE.logRenamedField(null, () -> null, Request.ALLOW_NO_JOBS, Request.ALLOW_NO_MATCH);
         }
         request.setAllowNoMatch(
             restRequest.paramAsBoolean(

+ 1 - 1
x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/rest/results/RestGetOverallBucketsAction.java

@@ -60,7 +60,7 @@ public class RestGetOverallBucketsAction extends BaseRestHandler {
                 request.setEnd(restRequest.param(Request.END.getPreferredName()));
             }
             if (restRequest.hasParam(Request.ALLOW_NO_JOBS)) {
-                LoggingDeprecationHandler.INSTANCE.usedDeprecatedName(
+                LoggingDeprecationHandler.INSTANCE.logRenamedField(
                     null, () -> null, Request.ALLOW_NO_JOBS, Request.ALLOW_NO_MATCH.getPreferredName());
             }
             request.setAllowNoMatch(

+ 7 - 6
x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java

@@ -779,24 +779,25 @@ public class ApiKeyService {
         }
 
         @Override
-        public void usedDeprecatedName(String parserName, Supplier<XContentLocation> location, String usedName, String modernName) {
+        public void logRenamedField(String parserName, Supplier<XContentLocation> location, String oldName, String currentName) {
             String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] ";
             deprecationLogger.deprecate(DeprecationCategory.API, "api_key_field",
-                "{}Deprecated field [{}] used in api key [{}], expected [{}] instead", prefix, usedName, apiKeyId, modernName);
+                "{}Deprecated field [{}] used in api key [{}], expected [{}] instead", prefix, oldName, apiKeyId, currentName);
         }
 
         @Override
-        public void usedDeprecatedField(String parserName, Supplier<XContentLocation> location, String usedName, String replacedWith) {
+        public void logReplacedField(String parserName, Supplier<XContentLocation> location, String oldName, String replacedName) {
             String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] ";
             deprecationLogger.deprecate(DeprecationCategory.API, "api_key_field",
-                "{}Deprecated field [{}] used in api key [{}], replaced by [{}]", prefix, usedName, apiKeyId, replacedWith);
+                "{}Deprecated field [{}] used in api key [{}], replaced by [{}]", prefix, oldName, apiKeyId, replacedName);
         }
 
         @Override
-        public void usedDeprecatedField(String parserName, Supplier<XContentLocation> location, String usedName) {
+        public void logRemovedField(String parserName, Supplier<XContentLocation> location, String removedName) {
             String prefix = parserName == null ? "" : "[" + parserName + "][" + location.get() + "] ";
             deprecationLogger.deprecate(DeprecationCategory.API, "api_key_field",
-                "{}Deprecated field [{}] used in api key [{}], which is unused and will be removed entirely", prefix, usedName, apiKeyId);
+                "{}Deprecated field [{}] used in api key [{}], which is unused and will be removed entirely",
+                prefix, removedName, apiKeyId);
         }
     }