Skip to content

Commit

Permalink
ARTEMIS-4655 report logging metrics
Browse files Browse the repository at this point in the history
It may be useful to configure alerts for ERROR or WARN events in the log
which may go unnoticed otherwise.
  • Loading branch information
jbertram authored and gemmellr committed Mar 5, 2024
1 parent b579134 commit 661a4e6
Show file tree
Hide file tree
Showing 13 changed files with 152 additions and 1 deletion.
Expand Up @@ -676,6 +676,9 @@ public static String getDefaultHapolicyBackupStrategy() {
// Whether or not to report uptime metrics
private static final boolean DEFAULT_UPTIME_METRICS = false;

// Whether or not to report logging metrics
private static final boolean DEFAULT_LOGGING_METRICS = false;

// How often (in ms) to scan for expired MQTT sessions
private static long DEFAULT_MQTT_SESSION_SCAN_INTERVAL = 500;

Expand Down Expand Up @@ -1865,6 +1868,13 @@ public static Boolean getDefaultUptimeMetrics() {
return DEFAULT_UPTIME_METRICS;
}

/**
* Whether or not to report logging metrics
*/
public static Boolean getDefaultLoggingMetrics() {
return DEFAULT_LOGGING_METRICS;
}

/**
* How often (in ms) to scan for expired MQTT sessions
*/
Expand Down
Expand Up @@ -30,6 +30,7 @@ public class MetricsConfiguration implements Serializable {
private boolean fileDescriptors = ActiveMQDefaultConfiguration.getDefaultFileDescriptorsMetrics();
private boolean processor = ActiveMQDefaultConfiguration.getDefaultProcessorMetrics();
private boolean uptime = ActiveMQDefaultConfiguration.getDefaultUptimeMetrics();
private boolean logging = ActiveMQDefaultConfiguration.getDefaultLoggingMetrics();
private ActiveMQMetricsPlugin plugin;

public boolean isJvmMemory() {
Expand Down Expand Up @@ -95,6 +96,15 @@ public MetricsConfiguration setUptime(boolean uptime) {
return this;
}

public boolean isLogging() {
return logging;
}

public MetricsConfiguration setLogging(boolean logging) {
this.logging = logging;
return this;
}

public ActiveMQMetricsPlugin getPlugin() {
return plugin;
}
Expand Down
Expand Up @@ -1012,6 +1012,8 @@ private void parseMetrics(final Element e, final Configuration config) {
metricsConfiguration.setProcessor(XMLUtil.parseBoolean(child));
} else if (child.getNodeName().equals("uptime")) {
metricsConfiguration.setUptime(XMLUtil.parseBoolean(child));
} else if (child.getNodeName().equals("logging")) {
metricsConfiguration.setLogging(XMLUtil.parseBoolean(child));
} else if (child.getNodeName().equals("plugin")) {
metricsConfiguration.setPlugin(parseMetricsPlugin(child, config));
}
Expand Down
Expand Up @@ -32,6 +32,7 @@
import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
import io.micrometer.core.instrument.binder.logging.Log4j2Metrics;
import io.micrometer.core.instrument.binder.system.FileDescriptorMetrics;
import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
import io.micrometer.core.instrument.binder.system.UptimeMetrics;
Expand Down Expand Up @@ -86,6 +87,9 @@ public MetricsManager(String brokerName,
if (metricsConfiguration.isUptime()) {
new UptimeMetrics().bindTo(meterRegistry);
}
if (metricsConfiguration.isLogging()) {
new Log4j2Metrics().bindTo(meterRegistry);
}
}
}

Expand Down
Expand Up @@ -4836,6 +4836,14 @@
</xsd:annotation>
</xsd:element>

<xsd:element name="logging" type="xsd:boolean" default="false" maxOccurs="1" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
whether or not to report logging metrics
</xsd:documentation>
</xsd:annotation>
</xsd:element>

<xsd:element name="plugin" maxOccurs="1" minOccurs="0">
<xsd:complexType>
<xsd:annotation>
Expand Down
Expand Up @@ -147,6 +147,8 @@ public void testDefaults() {
Assert.assertEquals(ActiveMQDefaultConfiguration.getDefaultProcessorMetrics(), conf.getMetricsConfiguration().isProcessor());

Assert.assertEquals(ActiveMQDefaultConfiguration.getDefaultUptimeMetrics(), conf.getMetricsConfiguration().isUptime());

Assert.assertEquals(ActiveMQDefaultConfiguration.getDefaultLoggingMetrics(), conf.getMetricsConfiguration().isLogging());
}

// Protected ---------------------------------------------------------------------------------------------
Expand Down
Expand Up @@ -584,6 +584,7 @@ public void testDefaults() {
assertTrue(metricsConfiguration.isFileDescriptors());
assertTrue(metricsConfiguration.isProcessor());
assertTrue(metricsConfiguration.isUptime());
assertTrue(metricsConfiguration.isLogging());
}

private void verifyAddresses() {
Expand Down
Expand Up @@ -384,6 +384,7 @@
<file-descriptors>true</file-descriptors>
<processor>true</processor>
<uptime>true</uptime>
<logging>true</logging>
<plugin class-name="org.apache.activemq.artemis.core.server.metrics.plugins.SimpleMetricsPlugin">
<property key="foo" value="x"/>
<property key="bar" value="y"/>
Expand Down
Expand Up @@ -265,6 +265,7 @@
<file-descriptors>true</file-descriptors>
<processor>true</processor>
<uptime>true</uptime>
<logging>true</logging>
<plugin class-name="org.apache.activemq.artemis.core.server.metrics.plugins.SimpleMetricsPlugin">
<property key="foo" value="x"/>
<property key="bar" value="y"/>
Expand Down
Expand Up @@ -22,6 +22,7 @@
<file-descriptors>true</file-descriptors>
<processor>true</processor>
<uptime>true</uptime>
<logging>true</logging>
<plugin class-name="org.apache.activemq.artemis.core.server.metrics.plugins.SimpleMetricsPlugin">
<property key="foo" value="x"/>
<property key="bar" value="y"/>
Expand Down
1 change: 1 addition & 0 deletions artemis-server/src/test/resources/metrics.xml
Expand Up @@ -27,6 +27,7 @@
<file-descriptors>true</file-descriptors>
<processor>true</processor>
<uptime>true</uptime>
<logging>true</logging>
<plugin class-name="org.apache.activemq.artemis.core.config.impl.FileConfigurationTest$FakeMetricPlugin">
<property key="key1" value="value1"/>
<property key="key2" value="value2"/>
Expand Down
13 changes: 12 additions & 1 deletion docs/user-manual/metrics.adoc
Expand Up @@ -118,13 +118,23 @@ Uptime::
Gauges process start time and uptime.
+
Disabled by default.
Logging::
Counts the number of logging events per logging category (e.g. `WARN`, `ERROR`, etc.).
+
Disabled by default.
+
[WARNING]
====
This works _exclusively_ with Log4j2 (i.e the default logging implementation shipped with the broker).
If you're embedding the broker and using a different logging implementation (e.g. Log4j 1.x, JUL, Logback, etc.) and you enable these metrics then the broker will fail to start with a `java.lang.NoClassDefFoundError` as it attempts to locate Log4j2 classes that don't exist on the classpath.
====
== Configuration
Metrics for all addresses and queues are enabled by default.
If you want to disable metrics for a particular address or set of addresses you can do so by setting the `enable-metrics` `address-setting` to `false`.
In `broker.xml` use the `metrics` element to configure which JVM metrics are reported and to configure the plugin itself.
In `broker.xml` use the `metrics` element to configure which general broker and JVM metrics are reported and to configure the plugin itself.
Here's a configuration with all optional metrics:
[,xml]
Expand All @@ -137,6 +147,7 @@ Here's a configuration with all optional metrics:
<file-descriptors>true</file-descriptors> <!-- defaults to false -->
<processor>true</processor> <!-- defaults to false -->
<uptime>true</uptime> <!-- defaults to false -->
<logging>true</logging> <!-- defaults to false -->
<plugin class-name="org.apache.activemq.artemis.core.server.metrics.plugins.LoggingMetricsPlugin"/>
</metrics>
----
Expand Down
@@ -0,0 +1,99 @@
/*
* 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 org.apache.activemq.artemis.tests.integration.plugin;

import java.lang.invoke.MethodHandles;

import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import org.apache.activemq.artemis.core.config.MetricsConfiguration;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.metrics.plugins.SimpleMetricsPlugin;
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoggingMetricsTest extends ActiveMQTestBase {

@Override
@Before
public void setUp() throws Exception {
super.setUp();
}

@Test
public void testLoggingMetrics() throws Exception {
final String idName = "log4j2.events";
final Tag brokerTag = Tag.of("broker", "localhost");
final String levelName = "level";
int start = 0;
String message = "";
ActiveMQServer server = createServer(false, createDefaultInVMConfig()
.setMetricsConfiguration(new MetricsConfiguration()
.setPlugin(new SimpleMetricsPlugin().init(null))
.setLogging(true)));
server.start();

Configurator.setLevel(MethodHandles.lookup().lookupClass(), Level.TRACE);
final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

Meter.Id trace = new Meter.Id(idName, Tags.of(brokerTag, Tag.of(levelName, "trace")), null, null, null);
assertTrue(MetricsPluginTest.getMetrics(server).containsKey(trace));
start = MetricsPluginTest.getMetrics(server).get(trace).intValue();
logger.trace(message);
logger.trace(message);
logger.trace(message);
assertEquals(3, MetricsPluginTest.getMetrics(server).get(trace).intValue() - start);

Meter.Id debug = new Meter.Id(idName, Tags.of(brokerTag, Tag.of(levelName, "debug")), null, null, null);
assertTrue(MetricsPluginTest.getMetrics(server).containsKey(debug));
start = MetricsPluginTest.getMetrics(server).get(debug).intValue();
logger.debug(message);
logger.debug(message);
logger.debug(message);
assertEquals(3, MetricsPluginTest.getMetrics(server).get(debug).intValue() - start);

Meter.Id info = new Meter.Id(idName, Tags.of(brokerTag, Tag.of(levelName, "info")), null, null, null);
assertTrue(MetricsPluginTest.getMetrics(server).containsKey(info));
start = MetricsPluginTest.getMetrics(server).get(info).intValue();
logger.info(message);
logger.info(message);
logger.info(message);
assertEquals(3, MetricsPluginTest.getMetrics(server).get(info).intValue() - start);

Meter.Id warn = new Meter.Id(idName, Tags.of(brokerTag, Tag.of(levelName, "warn")), null, null, null);
assertTrue(MetricsPluginTest.getMetrics(server).containsKey(warn));
start = MetricsPluginTest.getMetrics(server).get(warn).intValue();
logger.warn(message);
logger.warn(message);
logger.warn(message);
assertEquals(3, MetricsPluginTest.getMetrics(server).get(warn).intValue() - start);

Meter.Id error = new Meter.Id(idName, Tags.of(brokerTag, Tag.of(levelName, "error")), null, null, null);
assertTrue(MetricsPluginTest.getMetrics(server).containsKey(error));
start = MetricsPluginTest.getMetrics(server).get(error).intValue();
logger.error(message);
logger.error(message);
logger.error(message);
assertEquals(3, MetricsPluginTest.getMetrics(server).get(error).intValue() - start);
}
}

0 comments on commit 661a4e6

Please sign in to comment.