You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gr...@apache.org on 2024/05/22 17:33:43 UTC

(logging-log4j2) branch main updated: ported markers rewrite to 3.x (#2584)

This is an automated email from the ASF dual-hosted git repository.

grobmeier pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


The following commit(s) were added to refs/heads/main by this push:
     new 891c08e76a ported markers rewrite to 3.x (#2584)
891c08e76a is described below

commit 891c08e76ae8ad3ad5119272d9df027599bf445b
Author: Christian Grobmeier <cg...@grobmeier.de>
AuthorDate: Wed May 22 19:32:52 2024 +0200

    ported markers rewrite to 3.x (#2584)
---
 src/site/antora/antora.tmpl.yml                    |   1 +
 src/site/antora/antora.yml                         |   1 +
 .../examples/manual/markers/MarkerExample.java     |  63 ++++++
 .../ROOT/examples/manual/markers/log4j2.json       |  31 +++
 .../ROOT/examples/manual/markers/log4j2.properties |  34 ++++
 .../ROOT/examples/manual/markers/log4j2.xml        |  43 ++++
 .../ROOT/examples/manual/markers/log4j2.yaml       |  36 ++++
 .../examples/manual/markers/marker-filtering.log   |  23 +++
 .../antora/modules/ROOT/pages/manual/markers.adoc  | 221 +++++++++++++--------
 9 files changed, 371 insertions(+), 82 deletions(-)

diff --git a/src/site/antora/antora.tmpl.yml b/src/site/antora/antora.tmpl.yml
index afd7e6aba4..65e7d8d1a4 100644
--- a/src/site/antora/antora.tmpl.yml
+++ b/src/site/antora/antora.tmpl.yml
@@ -39,6 +39,7 @@ start_page: index.adoc
 asciidoc:
   attributes:
     # Commons
+    antora-examples-url: "https://raw.githubusercontent.com/apache/logging-log4j2/2.x/src/site/antora/modules/ROOT/examples"
     project-github-url: "${scm.url}"
     project-name: "Log4j"
     project-id: "log4j"
diff --git a/src/site/antora/antora.yml b/src/site/antora/antora.yml
index 50ccf7e30b..ce99130556 100644
--- a/src/site/antora/antora.yml
+++ b/src/site/antora/antora.yml
@@ -39,6 +39,7 @@ start_page: index.adoc
 asciidoc:
   attributes:
     # Commons
+    antora-examples-url: "https://raw.githubusercontent.com/apache/logging-log4j2/2.x/src/site/antora/modules/ROOT/examples"
     project-github-url: "https://github.com/apache/logging-log4j2"
     project-name: "Log4j"
     project-id: "log4j"
diff --git a/src/site/antora/modules/ROOT/examples/manual/markers/MarkerExample.java b/src/site/antora/modules/ROOT/examples/manual/markers/MarkerExample.java
new file mode 100644
index 0000000000..ef3f30c173
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/markers/MarkerExample.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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 example;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.MarkerManager;
+
+public final class MarkerExample {
+
+    private static final Logger logger = LogManager.getLogger("example.MarkerExample");
+    // tag::create-marker[]
+    private static final Marker SQL_MARKER = MarkerManager.getMarker("SQL");
+    // end::create-marker[]
+    // tag::create-marker-parent[]
+    private static final Marker QUERY_MARKER =
+            MarkerManager.getMarker("SQL_QUERY").addParents(SQL_MARKER);
+    private static final Marker UPDATE_MARKER =
+            MarkerManager.getMarker("UPDATE").addParents(SQL_MARKER);
+    // end::create-marker-parent[]
+
+    public static void main(final String[] args) {
+        doQuery("my_table");
+        doQueryParent("my_table");
+        doUpdate("my_table", "column", "value");
+    }
+
+    public static void doQuery(String table) {
+        // Do business logic here
+        // tag::use-marker[]
+        logger.debug(SQL_MARKER, "SELECT * FROM {}", table);
+        // end::use-marker[]
+    }
+
+    public static void doQueryParent(String table) {
+        // Do business logic here
+        // tag::use-marker-parent[]
+        logger.debug(QUERY_MARKER, "SELECT * FROM {}", table);
+        // end::use-marker-parent[]
+    }
+
+    public static void doUpdate(String table, String column, String value) {
+        // Do business logic here
+        // tag::use-marker-parent[]
+        logger.debug(UPDATE_MARKER, "UPDATE {} SET {} = {}", table, column, value);
+        // end::use-marker-parent[]
+    }
+}
diff --git a/src/site/antora/modules/ROOT/examples/manual/markers/log4j2.json b/src/site/antora/modules/ROOT/examples/manual/markers/log4j2.json
new file mode 100644
index 0000000000..01faa31bff
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/markers/log4j2.json
@@ -0,0 +1,31 @@
+{
+  "Configuration": {
+    "Appenders": {
+      "Console": {
+        "name": "SQL_LOG",
+        "PatternLayout": {
+          "pattern": "%d{HH:mm:ss.SSS} (%marker) %m%n"
+        }
+      }
+    },
+    "Loggers": {
+      "Root": {
+        "level": "INFO"
+      },
+      // tag::logger[]
+      "Logger": {
+        "name": "example",
+        "level": "ALL", // <1>
+        "AppenderRef": {
+          "ref": "SQL_LOG",
+          "MarkerFilter": { // <2>
+            "marker": "SQL",
+            "onMatch": "ACCEPT",
+            "onMismatch": "DENY"
+          }
+        }
+      }
+      // end::logger[]
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/site/antora/modules/ROOT/examples/manual/markers/log4j2.properties b/src/site/antora/modules/ROOT/examples/manual/markers/log4j2.properties
new file mode 100644
index 0000000000..5d7de97663
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/markers/log4j2.properties
@@ -0,0 +1,34 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF 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.
+#
+appender.0.type = Console
+appender.0.name = SQL_LOG
+appender.0.layout.type = PatternLayout
+appender.0.layout.pattern = %d{HH:mm:ss.SSS} (%marker) %m%n
+
+rootLogger.level = INFO
+
+# tag::logger[]
+logger.0.name = example
+# <1>
+logger.0.level = ALL
+logger.0.appenderRef.0.ref = SQL_LOG
+# <2>
+logger.0.appenderRef.0.filter.type = MarkerFilter
+logger.0.appenderRef.0.filter.marker = SQL
+logger.0.appenderRef.0.filter.onMatch = ACCEPT
+logger.0.appenderRef.0.filter.onMismatch = DENY
+# end::logger[]
diff --git a/src/site/antora/modules/ROOT/examples/manual/markers/log4j2.xml b/src/site/antora/modules/ROOT/examples/manual/markers/log4j2.xml
new file mode 100644
index 0000000000..d9f7094ae7
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/markers/log4j2.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF 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.
+  -->
+<Configuration xmlns="https://logging.apache.org/xml/ns"
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+               xsi:schemaLocation="
+                   https://logging.apache.org/xml/ns
+                   https://logging.apache.org/xml/ns/log4j-config-2.xsd">
+
+  <appenders>
+    <Console name="SQL_LOG">
+      <PatternLayout pattern="%d{HH:mm:ss.SSS} (%marker) %m%n"/>
+    </Console>
+  </appenders>
+
+  <loggers>
+    <root level="INFO"/>
+    <!-- tag::logger[] -->
+    <logger name="example" level="ALL"><!--1-->
+      <AppenderRef ref="SQL_LOG">
+        <MarkerFilter marker="SQL"
+                      onMatch="ACCEPT"
+                      onMismatch="DENY"/><!--2-->
+      </AppenderRef>
+    </logger>
+    <!-- end::logger[] -->
+  </loggers>
+
+</Configuration>
diff --git a/src/site/antora/modules/ROOT/examples/manual/markers/log4j2.yaml b/src/site/antora/modules/ROOT/examples/manual/markers/log4j2.yaml
new file mode 100644
index 0000000000..c3c5fee2ae
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/markers/log4j2.yaml
@@ -0,0 +1,36 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF 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.
+#
+Configuration:
+  Appenders:
+    Console:
+      name: "SQL_LOG"
+      PatternLayout:
+        pattern: "%d{HH:mm:ss.SSS} (%marker) %m%n"
+  Loggers:
+    Root:
+      level: "INFO"
+    # tag::logger[]
+    Logger:
+      name: "example"
+      level: "ALL" # <1>
+      AppenderRef:
+        ref: "SQL_LOG"
+        MarkerFilter: # <2>
+          marker: "SQL"
+          onMatch: "ACCEPT"
+          onMismatch: DENY
+    # end::logger[]
diff --git a/src/site/antora/modules/ROOT/examples/manual/markers/marker-filtering.log b/src/site/antora/modules/ROOT/examples/manual/markers/marker-filtering.log
new file mode 100644
index 0000000000..765998a113
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/markers/marker-filtering.log
@@ -0,0 +1,23 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF 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.
+#
+# tag::use-marker[]
+10:42:30.982 (SQL) SELECT * FROM my_table
+# end::use-marker[]
+# tag::use-marker-parent[]
+10:42:30.982 (SQL_QUERY[ SQL ]) SELECT * FROM my_table
+10:42:30.982 (SQL_UPDATE[ SQL ]) UPDATE my_table SET column = value
+# end::use-marker-parent[]
diff --git a/src/site/antora/modules/ROOT/pages/manual/markers.adoc b/src/site/antora/modules/ROOT/pages/manual/markers.adoc
index 41dc4245bd..ae863186eb 100644
--- a/src/site/antora/modules/ROOT/pages/manual/markers.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/markers.adoc
@@ -16,85 +16,142 @@
 ////
 = Markers
 
-One of the primary purpose of a logging framework is to provide the
-means to generate debugging and diagnostic information only when it is
-needed, and to allow filtering of that information so that it does not
-overwhelm the system or the individuals who need to make use of it. As
-an example, an application desires to log its entry, exit and other
-operations separately from SQL statements being executed, and wishes to
-be able to log queries separate from updates. One way to accomplish this
-is shown below:
-
-[source,java]
-----
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.MarkerManager;
-import java.util.Map;
-
-public class MyApp {
-
-    private Logger logger = LogManager.getLogger(MyApp.class.getName());
-    private static final Marker SQL_MARKER = MarkerManager.getMarker("SQL");
-    private static final Marker UPDATE_MARKER = MarkerManager.getMarker("SQL_UPDATE").setParents(SQL_MARKER);
-    private static final Marker QUERY_MARKER = MarkerManager.getMarker("SQL_QUERY").setParents(SQL_MARKER);
-
-    public String doQuery(String table) {
-        logger.traceEntry();
-
-        logger.debug(QUERY_MARKER, "SELECT * FROM {}", table);
-
-        String result = ... 
-
-        return logger.traceExit(result);
-    }
-
-    public String doUpdate(String table, Map<String, String> params) {
-        logger.traceEntry();
-
-        if (logger.isDebugEnabled()) {
-            logger.debug(UPDATE_MARKER, "UPDATE {} SET {}", table, formatCols());
-        }
-    
-        String result = ... 
-
-        return logger.traceExit(result);
-    }
-
-    private String formatCols(Map<String, String> cols) {
-        StringBuilder sb = new StringBuilder();
-        boolean first = true;
-        for (Map.Entry<String, String> entry : cols.entrySet()) {
-            if (!first) {
-                sb.append(", ");
-            }
-            sb.append(entry.getKey()).append("=").append(entry.getValue());
-            first = false;
-        }
-        return sb.toString();
-    }
-}
-----
-
-In the example above it is now possible to add MarkerFilters to only
-allow SQL update operations to be logged, all SQL updates to be logged
-or to log everything in MyApp.
-
-Some important rules about Markers must be considered when using them.
-
-1.  Markers must be unique. They are permanently registered by name so
-care should be taken to insure that Markers used in your application are
-distinct from those in the application's dependencies, unless that is
-what is desired.
-2.  Parent Markers can be added or removed dynamically. However, this is
-fairly expensive to do. Instead, it is recommended that the parents be
-identified when obtaining the Marker the first time as shown in the
-examples above. Specifically, the set method replaces all the markers in
-a single operation while add and remove act on only a single Marker at a
-time.
-3.  Evaluating Markers with multiple ancestors is much more expensive
-than Markers with no parents. For example, in one set of tests to
-evaluate whether a Marker matched its grandparent took 3 times longer
-than evaluating the Marker itself. Even then though, evaluating Markers
-is inexpensive compared to resolving the callers class name or line
-number.
+Markers allow to _tag_ log statements with a
+link:../javadoc/log4j-api/org/apache/logging/log4j/Marker.html[`Marker`]
+object, labeling them as belonging to a specific type.
+For example, developers can use markers to tag log statements related to a particular subsystem or functionality.
+
+By using markers, it is possible to filter log statements based on the `Marker`
+and display only those log statements that are of interest, such as those
+related to XML processing or SQL queries.
+
+Markers offer more fine-grained control over log filtering beyond log levels or package names.
+
+[#create]
+== Creating Markers
+
+[#simple-markers]
+=== Simple markers
+
+To create a `Marker`, create a field in your class using the `MarkerManager.getMarker()` method:
+
+[source, java, indent=0]
+----
+include::example$manual/markers/MarkerExample.java[tag=create-marker]
+----
+
+Since a `Marker` is reusable across multiple log statements, storing it in a `static final` field makes it a constant.
+Once created, use it as the first argument in the log statement:
+
+[source, java, indent=0]
+----
+include::example$manual/markers/MarkerExample.java[tag=use-marker]
+----
+
+If you use the <<example-configuration,configuration example below>>, one can see the following log statement on your console:
+
+[source, text]
+----
+include::example$manual/markers/marker-filtering.log[tag=use-marker]
+----
+
+[#hierarchy]
+=== Parent and child markers
+
+A marker can have zero or more parent markers, allowing for a hierarchy of markers.
+To create such a hierarchy, you must use the `addParents()` method on the `Marker` object after you make the child marker.
+
+[source, java, indent=0]
+----
+include::example$manual/markers/MarkerExample.java[tag=create-marker-parent]
+----
+
+Child markers do not differ from simple markers; one must pass them on as the first argument of a logging call.
+
+[source, java, indent=0]
+----
+include::example$manual/markers/MarkerExample.java[tag=use-marker-parent]
+----
+
+Messages marked with children's markers behave as if they were both marked with the children's marker and all its parents.
+If you use the <<example-configuration,configuration example below>>, you'll see the following log statement on your console:
+
+[source, text]
+----
+include::example$manual/markers/marker-filtering.log[tag=use-marker-parent]
+----
+
+[#configuring-log4j]
+== Configuring filtering
+
+Developers can use markers to filter the log statements delivered to log files.
+Marker processing is supported at least by
+https://logback.qos.ch/manual/filters.html#TurboFilter[Logback]
+and the Log4j Core logging backends.
+We will discuss only the configuration of the latter.
+
+To filter messages by marker, you need to add
+xref:manual/filters.adoc#MarkerFilter[`MarkerFilter`]
+to your configuration file.
+For example, one can use the snippet below to redirect all SQL-related logs to the `SQL_LOG` appender:
+
+[[example-configuration]]
+[tabs]
+====
+XML::
++
+[source, xml]
+----
+include::example$manual/markers/log4j2.xml[tag=logger]
+----
+
+JSON::
++
+[source, json]
+----
+include::example$manual/markers/log4j2.json[tag=logger]
+----
+
+YAML::
++
+[source, yaml]
+----
+include::example$manual/markers/log4j2.yaml[tag=logger]
+----
+
+Java properties::
++
+[source, properties]
+----
+include::example$manual/markers/log4j2.properties[tag=logger]
+----
+====
+
+<1> Match all messages from `example` package from all levels
+<2> Only allow messages marker with `SQL` or one of its children to be sent to the `SQL_LOG` appender.
+
+[#pitfalls]
+== Pitfalls
+
+It is important to note that marker names must be unique, as Log4j registers them permanently by name.
+Developers should avoid generic marker names, as they may conflict with
+those provided by third parties. Except, of course, if the user is aware of the implications.
+
+While it is possible to add or remove parent markers dynamically through the `setParents()` method,
+it is generally advisable to set the parents when the marker is created for efficiency and performance reasons.
+
+It is also worth noting that markers without parents are more efficient to evaluate
+than markers with multiple parents. It is generally a good idea to avoid
+complex hierarchies of markers where possible.
+
+[#complete-example]
+== Complete example
+
+To try the examples on this page:
+
+* add
+{antora-examples-url}/manual/markers/MarkerExample.java[MarkerExample.java]
+to the `src/main/java/example` folder of your project,
+* add
+{antora-examples-url}/manual/markers/log4j2.xml[log4j2.xml]
+to the `src/main/resources` folder of your project.