Last updated Mar 22, 2022

Adding metrics

Supported products

Your app can emit metrics to JMX while working with any product and version, no restrictions are placed on the platform MBean server. It's possible to create MBeans manually, but a metrics library like Micrometer Metrics or Dropwizard Metrics can speed up the development time.

Intended usage

Atlassian products emit metrics to JMX and we recommend our customers set up a monitoring solution for them. Customers can then either alert on metrics to proactively monitor the product and application, or refer to them to diagnose performance issues. You may wish for your app to also emit metrics in a similar fashion to ease adoption for customers.

Performance concerns

Every combination of metrics and tags (i.e. every resulting MBean in JMX) consumes memory. It's reasonable to assume that each MBean consumes an additional 300KB of memory. We recommend running a performance test with real data to ensure usage won't result in runaway memory consumption. To illustrate; if there are two metrics with different names, and they both have a tag with two possible values then the total memory consumption would be: (300KB * 2 tag values) + (300KB * 2 tag values) = 1.2MB.

Using Micrometer and Atlassian profiling to emit to JMX

  1. Add a dependency on Micrometer and Atlassian profiling's micrometer utilities. e.g if using maven;
1
2
<dependency>
    <groupId>com.atlassian.profiling</groupId>
    <artifactId>atlassian-profiling-micrometer</artifactId>
    <version>4.5.0</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-core</artifactId>
    <version>1.8.3</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-jmx</artifactId>
    <version>1.8.3</version>
    <scope>compile</scope>
</dependency>
  1. Avoid exporting the packages; com.atlassian.util.profiling.micrometer, io.micrometer, and com.codehale.metrics to OSGi. Learn more.

  2. The io.micrometer:micrometer-core artifact (specified above as a dependency) contains binary references to several third-party Java packages that Atlassian products don't actually use. When AMPS builds the JAR file for your app, those references will cause the maven-bundle-plugin to insert mandatory <Import-Package> entries for those packages into your app's META-INF/MANIFEST.MF file. Because those packages are not provided by the host Atlassian product, these mandatory entries cannot be satisfied, and your app will fail to load (there will be "missing OSGi package" errors in the product log, and your app will show as disabled in the Manage Apps page). You therefore need to suppress those package imports, by adding exclusions to the <Import-Package> directive within your AMPS <instructions>. Here are some of the exclusions you will most likely need to add; you may need to add others until your app loads successfully:

1
2
<configuration>
    <instructions>
        <Import-Package>
            !ch.qos.logback.*,
            !com.mongodb.*,
            !com.netflix.*,
            !org.apache.kafka.*,
            ... (and so on)
        </Import-Package>
    </instructions>
</configuration>
  1. Choose a unique domain for your app, all metrics created will appear under this domain e.g com.atlassian.teamcalendars

  2. Create a Micrometer MeterRegistry bean to be reused for creating all metrics, e.g

1
2
// Package imports here to show the relationships between Atlassian Profiling, Micrometer, and Dropwizard
import com.atlassian.jira.monitoring.jmx.JmxMetricsExposer;
import com.atlassian.util.profiling.micrometer.util.QualifiedCompatibleHierarchicalNameMapper;
import com.atlassian.util.profiling.micrometer.util.UnescapedObjectNameFactory;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.jmx.JmxReporter;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
import io.micrometer.jmx.JmxConfig;
import io.micrometer.jmx.JmxMeterRegistry;

// ...

@Bean
public MeterRegistry jmxMeterRegistry() {
    final MetricRegistry jmxMetricRegistry = new MetricRegistry();
    final JmxReporter jmxReporter = JmxReporter.forRegistry(jmxMetricRegistry)
        .inDomain("com.atlassian.teamcalendars")
        .createsObjectNamesWith(new UnescapedObjectNameFactory())
        .build();
    final JmxMeterRegistry jmxMeterRegistry = new JmxMeterRegistry(
        JmxConfig.DEFAULT,
        Clock.SYSTEM,
        new QualifiedCompatibleHierarchicalNameMapper(),
        jmxMetricRegistry,
        jmxReporter);
    jmxMeterRegistry.config().namingConvention(NamingConvention.dot)
    jmxMeterRegistry.start();
    return jmxMeterRegistry;
}
  1. Follow the Micrometer documentation to add the metric you want using the jmxMeterRegistry, e.g
1
2
addEvent();
jmxMeterRegistry.counter("addEvent").increment(1L);

Example in JConsole

You can use JConsole to attach to a running JVM to see the metric emitted to JMX. In this particular example com.atlassian.confluence is the domain, name=getFooCount is the metric name, and tag.entity=foo is a tag with the key "entity" and the value "foo".

Rate this page: