From d496304858f6349989729619ddc41460b77ef16c Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Fri, 9 Sep 2022 15:51:44 -0700 Subject: [PATCH 01/20] JMX Metric Insight Solving https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/6131 (JMX Support). --- .../RuntimeMetricsInstaller.java | 29 +- .../runtime-metrics/library/README.md | 270 ++++++++++ .../runtime-metrics/library/activemq.md | 17 + .../runtime-metrics/library/build.gradle.kts | 4 + .../runtime-metrics/library/hadoop.md | 15 + .../runtime-metrics/library/jetty.md | 16 + .../runtime-metrics/library/kafka-broker.md | 32 ++ .../runtime-metrics/library/kafka-consumer.md | 28 ++ .../runtime-metrics/library/kafka-producer.md | 24 + .../runtimemetrics/jmx/AttributeInfo.java | 53 ++ .../jmx/AttributeValueExtractor.java | 227 +++++++++ .../runtimemetrics/jmx/BeanFinder.java | 130 +++++ .../runtimemetrics/jmx/BeanPack.java | 39 ++ .../runtimemetrics/jmx/DetectionStatus.java | 33 ++ .../runtimemetrics/jmx/LabelExtractor.java | 18 + .../runtimemetrics/jmx/MetricBanner.java | 59 +++ .../jmx/MetricConfiguration.java | 31 ++ .../runtimemetrics/jmx/MetricDef.java | 50 ++ .../runtimemetrics/jmx/MetricExtractor.java | 54 ++ .../runtimemetrics/jmx/MetricLabel.java | 51 ++ .../runtimemetrics/jmx/MetricRegistrar.java | 191 ++++++++ .../runtimemetrics/jmx/MetricService.java | 101 ++++ .../jmx/conf/data/JmxConfig.java | 46 ++ .../runtimemetrics/jmx/conf/data/JmxRule.java | 195 ++++++++ .../runtimemetrics/jmx/conf/data/Metric.java | 66 +++ .../jmx/conf/data/MetricStructure.java | 130 +++++ .../jmx/conf/yaml/RuleParser.java | 90 ++++ .../main/resources/jmx/rules/activemq.yaml | 66 +++ .../src/main/resources/jmx/rules/hadoop.yaml | 63 +++ .../src/main/resources/jmx/rules/jetty.yaml | 54 ++ .../resources/jmx/rules/kafka-broker.yaml | 205 ++++++++ .../resources/jmx/rules/kafka-consumer.yaml | 80 +++ .../resources/jmx/rules/kafka-producer.yaml | 63 +++ .../src/main/resources/jmx/rules/tomcat.yaml | 67 +++ .../src/main/resources/jmx/rules/wildfly.yaml | 83 ++++ .../jmx/AttributeExtractorTest.java | 205 ++++++++ .../runtimemetrics/jmx/RuleParserTest.java | 461 ++++++++++++++++++ .../runtime-metrics/library/tomcat.md | 13 + .../runtime-metrics/library/wildfly.md | 18 + 39 files changed, 3365 insertions(+), 12 deletions(-) create mode 100644 instrumentation/runtime-metrics/library/README.md create mode 100644 instrumentation/runtime-metrics/library/activemq.md create mode 100644 instrumentation/runtime-metrics/library/hadoop.md create mode 100644 instrumentation/runtime-metrics/library/jetty.md create mode 100644 instrumentation/runtime-metrics/library/kafka-broker.md create mode 100644 instrumentation/runtime-metrics/library/kafka-consumer.md create mode 100644 instrumentation/runtime-metrics/library/kafka-producer.md create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeInfo.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeValueExtractor.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanFinder.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanPack.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/DetectionStatus.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/LabelExtractor.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricBanner.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricConfiguration.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricDef.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricExtractor.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricLabel.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricRegistrar.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricService.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxConfig.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxRule.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/Metric.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/MetricStructure.java create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/yaml/RuleParser.java create mode 100644 instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/activemq.yaml create mode 100644 instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/hadoop.yaml create mode 100644 instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/jetty.yaml create mode 100644 instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-broker.yaml create mode 100644 instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-consumer.yaml create mode 100644 instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-producer.yaml create mode 100644 instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/tomcat.yaml create mode 100644 instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/wildfly.yaml create mode 100644 instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeExtractorTest.java create mode 100644 instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/RuleParserTest.java create mode 100644 instrumentation/runtime-metrics/library/tomcat.md create mode 100644 instrumentation/runtime-metrics/library/wildfly.md diff --git a/instrumentation/runtime-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/RuntimeMetricsInstaller.java b/instrumentation/runtime-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/RuntimeMetricsInstaller.java index 025e2298d04a..fe01ce23d757 100644 --- a/instrumentation/runtime-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/RuntimeMetricsInstaller.java +++ b/instrumentation/runtime-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/RuntimeMetricsInstaller.java @@ -14,6 +14,7 @@ import io.opentelemetry.instrumentation.runtimemetrics.GarbageCollector; import io.opentelemetry.instrumentation.runtimemetrics.MemoryPools; import io.opentelemetry.instrumentation.runtimemetrics.Threads; +import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricService; import io.opentelemetry.javaagent.extension.AgentListener; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -27,21 +28,25 @@ public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { ConfigProperties config = autoConfiguredSdk.getConfig(); boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); - if (!config.getBoolean("otel.instrumentation.runtime-metrics.enabled", defaultEnabled)) { - return; - } + if (config.getBoolean("otel.instrumentation.runtime-metrics.enabled", defaultEnabled)) { + + OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); - OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); + BufferPools.registerObservers(openTelemetry); + Classes.registerObservers(openTelemetry); + Cpu.registerObservers(openTelemetry); + MemoryPools.registerObservers(openTelemetry); + Threads.registerObservers(openTelemetry); - BufferPools.registerObservers(openTelemetry); - Classes.registerObservers(openTelemetry); - Cpu.registerObservers(openTelemetry); - MemoryPools.registerObservers(openTelemetry); - Threads.registerObservers(openTelemetry); + if (config.getBoolean( + "otel.instrumentation.runtime-metrics.experimental-metrics.enabled", false)) { + GarbageCollector.registerObservers(openTelemetry); + } + } - if (config.getBoolean( - "otel.instrumentation.runtime-metrics.experimental-metrics.enabled", false)) { - GarbageCollector.registerObservers(openTelemetry); + if (config.getBoolean("otel.jmx.enabled", true)) { + MetricService service = new MetricService(GlobalOpenTelemetry.get(), config); + service.start(); } } } diff --git a/instrumentation/runtime-metrics/library/README.md b/instrumentation/runtime-metrics/library/README.md new file mode 100644 index 000000000000..781f08adcd77 --- /dev/null +++ b/instrumentation/runtime-metrics/library/README.md @@ -0,0 +1,270 @@ +# JMX Metric Insight + +This subsystem provides a framework for collecting and reporting metrics provided by +[JMX](https://www.oracle.com/technical-resources/articles/javase/jmx.html) through +local [MBeans](https://docs.oracle.com/javase/tutorial/jmx/mbeans/index.html) +available within the instrumented application. The required MBeans and corresponding metrics can be described using a YAML configuration file. The individual metric configurations allow precise metric selection and identification. + +The selected JMX metrics are reported using the Java Agent internal SDK. This means that they share the configuration and metric exporter with other metrics collected by the agent and are controlled by the same properties, for example `otel.metric.export.interval` or `otel.metrics.exporter`. +The Open Telemetry resource description for the metrics reported by JMX Metric Insight will be the same as for other metrics exported by the SDK, while the instrumentation scope will be `io.opentelemetry.jmx`. + +## Predefined metrics + +JMX Metric Insight comes with a number of predefined configurations containing curated sets of JMX metrics for popular application servers or frameworks. To enable collection for the predefined metrics, specify a list of targets as the value for the `otel.jmx.target.system` property. For example + +```bash +$ java -javaagent:path/to/opentelemetry-javaagent.jar \ + -Dotel.jmx.target.system=kafka-broker,kafka-consumer \ + ... \ + -jar myapp.jar +``` + +No targets are enabled by default. The supported target environments are listed below. + + - [activemq](activemq.md) + - [jetty](jetty.md) + - [kafka-broker](kafka-broker.md) + - [kafka-consumer](kafka-consumer.md) + - [kafka-producer](kafka-producer.md) + - [tomcat](tomcat.md) + - [wildfly](wildfly.md) + - [hadoop](hadoop.md) + +## Configuration File + +To provide your own metric definitions, create a YAML configuration file, and specify its location using the `otel.jmx.config` property. For example + +```bash +$ java -javaagent:path/to/opentelemetry-javaagent.jar \ + -Dotel.jmx.config=path/to/config_file.yaml \ + ... \ + -jar myapp.jar +``` + +### Basic Syntax + +The configuration file can contain multiple entries (which we call _rules_), defining a number of metrics. Each rule must identify a set of MBeans and the name of the MBean attribute to query, along with additional information on how to report the values. Let's look at a simple example. +```yaml +--- +rules: + - bean: java.lang:type=Threading + mapping: + ThreadCount: + metric: jvm.thread.count + type: updowncounter + desc: The current number of threads + unit: 1 +``` +MBeans are identified by unique [ObjectNames](https://docs.oracle.com/javase/8/docs/api/javax/management/ObjectName.html). In the example above, the object name `java.lang:type=Threading` identifies one of the standard JVM MBeans, which can be used to access a number of internal JVM statistics related to threads. For that MBean, we specify its attribute `ThreadCount` which reflects the number of currently active (alive) threads. The values of this attribute will be reported by a metric named `jvm.thread.count`. The declared OpenTelemetry type of the metric is declared as `updowncounter` which indicates that the value is a sum which can go up or down over time. Metric description and/or unit can also be specified. + +All metrics reported by the service are backed by +[asynchronous instruments](https://opentelemetry.io/docs/reference/specification/metrics/api/#synchronous-and-asynchronous-instruments) which can be a +[Counter](https://opentelemetry.io/docs/reference/specification/metrics/api/#asynchronous-counter), +[UpDownCounter](https://opentelemetry.io/docs/reference/specification/metrics/api/#asynchronous-updowncounter), or a +[Gauge](https://opentelemetry.io/docs/reference/specification/metrics/api/#asynchronous-gauge) (the default). + +To figure out what MBeans (or ObjectNames) and their attributes are available for your system, check its documentation, or use a universal MBean browsing tool, such as `jconsole`, available for every JDK version. + +### Composite Types + +The next example shows how the current heap size can be reported. +```yaml +--- +rules: + - bean: java.lang:type=Memory + mapping: + HeapMemoryUsage.used: + metric: jvm.heap.used + type: updowncounter + desc: The current heap size + unit: B + HeapMemoryUsage.max: + metric: jvm.heap.max + type: updowncounter + desc: The maximum allowed heap size + unit: B +``` +The MBean responsible for memory statistics, identified by ObjectName `java.lang:type=Memory` has an attribute named `HeapMemoryUsage`, which is of a `CompositeType`. This type represents a collection of fields with values (very much like the traditional `struct` data type). To access individual fields of the structure we use a dot which separates the MBean attribute name from the field name. The values are reported in bytes, which here we indicate by `B`. In the above example, the current heap size and the maximum allowed heap size will be reported as two metrics, named `jvm.heap.used`, and `jvm.heap.max`. + +### Measurement Attributes + +A more advanced example shows how to report similar metrics related to individual memory pools. A JVM can use a number of memory pools, some of them are part of the heap, and some are for JVM internal use. The number and the names of the memory pools depend on the JVM vendor, the Java version, and may even depend on the java command line options. Since the memory pools, in general, are unknown, we will use wildcard character for specifying memory pool name (in other words, we will use what is known as an ObjectName pattern). + +```yaml +--- +rules: + - bean: java.lang:name=*,type=MemoryPool + label: + pool: param(name) + type: attrib(Type) + mapping: + Usage.used: + metric: jvm.memory.pool.used + type: updowncounter + desc: Pool memory currently used + unit: B + Usage.max: + metric: jvm.memory.pool.max + type: updowncounter + desc: Maximum obtainable memory pool size + unit: B +``` + +The ObjectName pattern will match a number of MBeans, each for a different memory pool. The number and names of available memory pools, however, will be known only at runtime. To report values for all actual memory pools using only two metrics, we use metric attributes (referenced by the configuration file as `label`s). The first metric attribute, named `pool` will have its value derived from the ObjectName parameter `name` - which corresponds to the memory pool name. The second metric attribute, named `type` will get its value from the corresponding MBean attribute named `Type`. The values of this attribute are strings `HEAP` or `NON_HEAP` classifying the corresponding memory pool. Here the definition of the metric attributes is shared by both metrics, but it is also possible to define them at the individual metric level. + +Using the above rule, when running on HotSpot JVM for Java 11, the following combinations of metric attributes will be reported. + - {pool="Compressed Class Space", type="NON_HEAP"} + - {pool="CodeHeap 'non-profiled nmethods'", type="NON_HEAP"} + - {pool="G1 Eden Space", type="HEAP"} + - {pool="G1 Old Gen", type="HEAP"} + - {pool="CodeHeap 'profiled nmethods'", type="NON_HEAP"} + - {pool="Metaspace", type="NON_HEAP"} + - {pool="CodeHeap 'non-nmethods'", type="NON_HEAP"} + - {pool="G1 Survivor Space", type="HEAP"} + +### Mapping multiple MBean attributes to the same metric + +Sometimes it is desired to merge several MBean attributes into a single metric, as shown in the next example. + +```yaml +--- +rules: + - bean: Catalina:type=GlobalRequestProcessor,name=* + label: + handler: param(name) + type: counter + mapping: + bytesReceived: + metric: catalina.traffic + label: + direction: in + desc: The number of transmitted bytes + unit: B + bytesSent: + metric: catalina.traffic + label: + direction: out + desc: The number of transmitted bytes + unit: B +``` +The referenced MBean has two attributes of interest, `bytesReceived`, and `bytesSent`. We want them to be reported by just one metric, but keeping the values separate by using metric attribute `direction`. This is achieved by specifying the same metric name `catalina.traffic` when mapping the MBean attributes to metrics. There will be two metric attributes provided: `handler`, which has a shared definition, and `direction`, which has its value (`in` or `out`) declared directly, depending on the MBean attribute providing the metric value. + +Keep in mind that when defining a metric multiple times like this, its type, unit and description must be exactly the same. Otherwise there will be complaints about attempts to redefine a metric in a non-compatible way. +The example also demonstrates that when specifying a number of MBean attribute mappings within the same rule, the metric type can be declared only once (outside of the `mapping` section). + +Even when not reusing the metric name, special care also has to be taken when using ObjectName patterns (or specifying multiple ObjectNames). Different ObjectNames matching the pattern must result in using different metric attributes. Otherwise the same metric will be reported multiple times (using different values), which will likely clobber the previous values. + +### Making shortcuts + +While it is possible to define MBeans based metrics with fine details, sometimes it is desirable to provide the rules in compact format, minimizing the editing effort, but maintaining their efficiency and accuracy. The accepted YAML syntax allows to define some metric properties once per rule, which may lead to reduction in the amount of typing. This is especially visible if many related MBean attributes need to be covered, and is illustrated by the following example. + +```yaml +--- +rules: + - bean: kafka.streams:type=stream-thread-metrics,thread-id=* + label: + threadId: param(thread-id) + prefix: kafka.streams. + unit: ms + mapping: + commit-latency-avg: + commit-latency-max: + poll-latency-avg: + poll-latency-max: + process-latency-avg: + process-latency-max: + punctuate-latency-avg: + punctuate-latency-max: + poll-records-avg: + unit: 1 + poll-records-max: + unit: 1 + - bean: kafka.streams:type=stream-thread-metrics,thread-id=* + label: + threadId: param(thread-id) + prefix: kafka.streams. + unit: /s + type: gauge + mapping: + commit-rate: + process-rate: + task-created-rate: + task-closed-rate: + skipped-records-rate: + - bean: kafka.streams:type=stream-thread-metrics,thread-id=* + label: + threadId: param(thread-id) + prefix: kafka.streams.totals. + unit: 1 + type: counter + mapping: + commit-total: + poll-total: + process-total: + task-created-total: + task-closed-total: +``` +Because we declared metric prefix (here `kafka.streams.`) and did not specify actual metric names, the metric names will be generated automatically, by appending the corresponding MBean attribute name to the prefix. +Thus, the above definitions will create several metrics, named `kafka.streams.commit-latency-avg`, `kafka.streams.commit-latency-max`, and so on. For the first configuration rule, the default unit has been changed to `ms`, which remains in effect for all attribute mappings listed within the rule, unless they define their own unit. Similarly, the second configuration rule defines the unit as `/s`, valid for all the rates reported. + +The metric descriptions will remain undefined, unless they are provided by the queried MBeans. + +### General syntax + +Here is the general description of the accepted configuration file syntax. The whole contents of the file is case-sensitive, with exception for `type` as described in the table below. + +```yaml +--- +rules: # start of list of configuration rules + - bean: # can contain wildcards + label: # optional metric attributes, they apply to all metrics below + : param() # is used as the key to extract value from actual ObjectName + : attrib() # is used as the attribute name to extract value from MBean + prefix: # optional, useful for avoiding specifying metric names below + unit: # optional, redefines the default unit for the whole rule + type: # optional, redefines the default type for the whole rule + mapping: + : # an MBean attribute name defining the metric value + metric: # metric name will be + type: # optional, the default type is gauge + desc: # optional + unit: # optional + label: # optional, will be used in addition to the shared labels above + : # direct value for the label + : # use a.b to get access into CompositeData + metric: # optional, the default is the MBean attribute name + unit: # optional + : # metric name will be + : # metric name will be + - beans: # alternatively, if multiple object names are needed + - # at least one object name must be specified + - + mapping: + : # an MBean attribute name defining the metric value + metric: # metric name will be + type: updowncounter # optional + : # metric name will be +``` +The following table explains the used terms with more details. + +| Syntactic Element | Description | +| ---------------- | --------------- | +| OBJECTNAME | A syntactically valid string representing an ObjectName (see [ObjectName constructor](https://docs.oracle.com/javase/8/docs/api/javax/management/ObjectName.html#ObjectName-java.lang.String-) ). | +| LABEL | Any well-formed string that can be used as a metric [attribute](https://opentelemetry.io/docs/reference/specification/common/#attribute) key. | +| ATTRIB | A non-empty string used as a name of the MBean attribute. The attribute value must be a String, otherwise the specified label (metric attribute) will not be used. | +| PARAM | A non-empty string used as a property key for the ObjectName identifying the MBean which provides the metric value. If the ObjectName does not have a property with the given key, the specified label will not be used. | +| METRIC_NAME_PREFIX | Any non-empty string which will be prepended to the specified metric (instrument) names. | +| METRIC_NAME | Any non-empty string. The string, prefixed by the optional prefix (see above) must satisfy [instrument naming rule](https://opentelemetry.io/docs/reference/specification/metrics/api/#instrument-naming-rule). | +| TYPE | One of `counter`, `updowncounter`, or `gauge`. The default is `gauge`. This value is case insensitive. | +| DESCRIPTION | Any string to be used as human-readable [description](https://opentelemetry.io/docs/reference/specification/metrics/api/#instrument-description) of the metric. If the description is not provided by the rule, an attempt will be made to extract one automatically from the corresponding MBean. | +| UNIT | A string identifying the [unit](https://opentelemetry.io/docs/reference/specification/metrics/api/#instrument-unit) of measurements reported by the metric. Enclose the string in single or double quotes if using unit annotations. | +| STRING | Any string to be used directly as the label value. | +| ATTRIBUTE | A non-empty string representing the MBean attribute defining the metric value. The attribute value must be a number. Special dot-notation _attributeName.itemName_ can be used to access numerical items within attributes of [CompositeType](https://docs.oracle.com/javase/8/docs/api/javax/management/openmbean/CompositeType.html). | + +## Assumptions and Limitations + +This version of JMX Metric Insight has a number of limitations. + +- Attributes with the same name but belonging to different MBeans described by a single metric rule must have the same type (long or double). +- All MBeans which are described by the specified ObjectNames in a single rule must be registered with the same MBeanServer instance. +- While MBeanServers and MBeans can be created dynamically by the application, it is assumed that they will live indefinitely. Their disappearance may not be recognized properly, and may lead to some memory leaks. diff --git a/instrumentation/runtime-metrics/library/activemq.md b/instrumentation/runtime-metrics/library/activemq.md new file mode 100644 index 000000000000..8cdc14dec307 --- /dev/null +++ b/instrumentation/runtime-metrics/library/activemq.md @@ -0,0 +1,17 @@ +# ActiveMQ Metrics + +Here is the list of metrics based on MBeans exposed by ActiveMQ. + +| Metric Name | Type | Attributes | Description | +| ---------------- | --------------- | ---------------- | --------------- | +| activemq.ProducerCount | UpDownCounter | destination, broker | The number of producers attached to this destination | +| activemq.ConsumerCount | UpDownCounter | destination, broker | The number of consumers subscribed to this destination | +| activemq.memory.MemoryPercentUsage | Gauge | destination, broker | The percentage of configured memory used | +| activemq.message.QueueSize | UpDownCounter | destination, broker | The current number of messages waiting to be consumed | +| activemq.message.ExpiredCount | Counter | destination, broker | The number of messages not delivered because they expired | +| activemq.message.EnqueueCount | Counter | destination, broker | The number of messages sent to this destination | +| activemq.message.DequeueCount | Counter | destination, broker | The number of messages acknowledged and removed from this destination | +| activemq.message.AverageEnqueueTime | Gauge | destination, broker | The average time a message was held on this destination | +| activemq.connections.CurrentConnectionsCount | UpDownCounter | | The total number of current connections | +| activemq.disc.StorePercentUsage | Gauge | | The percentage of configured disk used for persistent messages | +| activemq.disc.TempPercentUsage | Gauge | | The percentage of configured disk used for non-persistent messages | diff --git a/instrumentation/runtime-metrics/library/build.gradle.kts b/instrumentation/runtime-metrics/library/build.gradle.kts index 34d3651cdc0a..44514a4931da 100644 --- a/instrumentation/runtime-metrics/library/build.gradle.kts +++ b/instrumentation/runtime-metrics/library/build.gradle.kts @@ -3,6 +3,10 @@ plugins { } dependencies { + implementation("org.yaml:snakeyaml:1.30") + + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") + testImplementation("io.opentelemetry:opentelemetry-sdk-metrics") testImplementation(project(":testing-common")) } diff --git a/instrumentation/runtime-metrics/library/hadoop.md b/instrumentation/runtime-metrics/library/hadoop.md new file mode 100644 index 000000000000..7e628fe0464a --- /dev/null +++ b/instrumentation/runtime-metrics/library/hadoop.md @@ -0,0 +1,15 @@ +# Hadoop Metrics + +Here is the list of metrics based on MBeans exposed by Hadoop. + +| Metric Name | Type | Attributes | Description | +|-----------------------------------|---------------|------------------|-------------------------------------------------------| +| hadoop.capacity.CapacityUsed | UpDownCounter | node_name | Current used capacity across all data nodes | +| hadoop.capacity.CapacityTotal | UpDownCounter | node_name | Current raw capacity of data nodes | +| hadoop.block.BlocksTotal | UpDownCounter | node_name | Current number of allocated blocks in the system | +| hadoop.block.MissingBlocks | UpDownCounter | node_name | Current number of missing blocks | +| hadoop.block.CorruptBlocks | UpDownCounter | node_name | Current number of blocks with corrupt replicas | +| hadoop.volume.VolumeFailuresTotal | UpDownCounter | node_name | Total number of volume failures across all data nodes | +| hadoop.file.FilesTotal | UpDownCounter | node_name | Current number of files and directories | +| hadoop.file.TotalLoad | UpDownCounter | node_name | Current number of connection | +| hadoop.datanode.Count | UpDownCounter | node_name, state | The Number of data nodes | diff --git a/instrumentation/runtime-metrics/library/jetty.md b/instrumentation/runtime-metrics/library/jetty.md new file mode 100644 index 000000000000..646edaea29aa --- /dev/null +++ b/instrumentation/runtime-metrics/library/jetty.md @@ -0,0 +1,16 @@ +# Jetty Metrics + +Here is the list of metrics based on MBeans exposed by Jetty. + +| Metric Name | Type | Attributes | Description | +|--------------------------------|---------------|--------------|------------------------------------------------------| +| jetty.session.sessionsCreated | Counter | resource | The number of sessions established in total | +| jetty.session.sessionTimeTotal | UpDownCounter | resource | The total time sessions have been active | +| jetty.session.sessionTimeMax | UpDownCounter | resource | The maximum amount of time a session has been active | +| jetty.session.sessionTimeMean | Gauge | resource | The mean time sessions remain active | +| jetty.threads.busyThreads | UpDownCounter | | The current number of busy threads | +| jetty.threads.idleThreads | UpDownCounter | | The current number of idle threads | +| jetty.threads.maxThreads | UpDownCounter | | The maximum number of threads in the pool | +| jetty.threads.queueSize | UpDownCounter | | The current number of threads in the queue | +| jetty.io.selectCount | Counter | resource, id | The number of select calls | +| jetty.logging.LoggerCount | UpDownCounter | | The number of registered loggers by name | diff --git a/instrumentation/runtime-metrics/library/kafka-broker.md b/instrumentation/runtime-metrics/library/kafka-broker.md new file mode 100644 index 000000000000..beac186a4f1e --- /dev/null +++ b/instrumentation/runtime-metrics/library/kafka-broker.md @@ -0,0 +1,32 @@ +# Kafka Broker Metrics + +Here is the list of metrics based on MBeans exposed by Kafka broker.

+Broker metrics: + +| Metric Name | Type | Attributes | Description | +|------------------------------------|---------------|------------|----------------------------------------------------------------------| +| kafka.message.count | Counter | | The number of messages received by the broker | +| kafka.request.count | Counter | type | The number of requests received by the broker | +| kafka.request.failed | Counter | type | The number of requests to the broker resulting in a failure | +| kafka.request.time.total | Counter | type | The total time the broker has taken to service requests | +| kafka.request.time.50p | Gauge | type | The 50th percentile time the broker has taken to service requests | +| kafka.request.time.99p | Gauge | type | The 99th percentile time the broker has taken to service requests | +| kafka.request.queue | UpDownCounter | | Size of the request queue | +| kafka.network.io | Counter | direction | The bytes received or sent by the broker | +| kafka.purgatory.size | UpDownCounter | type | The number of requests waiting in purgatory | +| kafka.partition.count | UpDownCounter | | The number of partitions on the broker | +| kafka.partition.offline | UpDownCounter | | The number of partitions offline | +| kafka.partition.underReplicated | UpDownCounter | | The number of under replicated partitions | +| kafka.isr.operation.count | UpDownCounter | operation | The number of in-sync replica shrink and expand operations | +| kafka.lag.max | Counter | | The max lag in messages between follower and leader replicas | +| kafka.controller.active.count | UpDownCounter | | The number of controllers active on the broker | +| kafka.leaderElection.count | Counter | | The leader election count | +| kafka.leaderElection.unclean.count | Counter | | Unclean leader election count - increasing indicates broker failures | +
+Log metrics: + +| Metric Name | Type | Attributes | Description | +|---------------------------|---------|------------|----------------------------------| +| kafka.logs.flush.count | Counter | | Log flush count | +| kafka.logs.flush.time.50p | Gauge | | Log flush time - 50th percentile | +| kafka.logs.flush.time.99p | Gauge | | Log flush time - 99th percentile | diff --git a/instrumentation/runtime-metrics/library/kafka-consumer.md b/instrumentation/runtime-metrics/library/kafka-consumer.md new file mode 100644 index 000000000000..c591ac6e0bac --- /dev/null +++ b/instrumentation/runtime-metrics/library/kafka-consumer.md @@ -0,0 +1,28 @@ +# Kafka Consumer Metrics + +Here is the list of metrics based on MBeans exposed by Kafka consumer.

+ +Consumer metrics: + +| Metric Name | Type | Attributes | Description | +|---------------------------------------------------|-------|------------------|--------------------------------------------------------------------------------| +| kafka.consumer.all.rebalance-latency-avg | Gauge | client-id | The average time taken for a group to complete a successful rebalance | +| kafka.consumer.all.rebalance-latency-max | Gauge | client-id | The maximum time taken for a group to complete a successful rebalance | +| kafka.consumer.all.rebalance-latency-total | Gauge | client-id | The total time this consumer has spent in successful rebalances since creation | +| kafka.consumer.all.rebalance-rate-per-hour | Gauge | client-id | The number of successful rebalance events per hour | +| kafka.consumer.all.rebalance-total | Gauge | client-id | The total number of successful rebalance events | +| kafka.consumer.all.last-rebalance-seconds-ago | Gauge | client-id | Number of seconds since the last rebalance event | +| kafka.consumer.all.failed-rebalance-rate-per-hour | Gauge | client-id | Number of failed rebalance events per hour | +| kafka.consumer.all.failed-rebalance-total | Gauge | client-id | Total number of failed rebalance events | +| kafka.consumer.all.commit-latency-avg | Gauge | client-id | The average time taken for a commit request | +| kafka.consumer.all.commit-rate | Gauge | client-id | The number of commit calls per second | +| kafka.consumer.all.fetch-rate | Gauge | client-id | The number of fetch requests for all topics per second | +| kafka.consumer.all.fetch-size-avg | Gauge | client-id | The average number of bytes fetched per request for all topics | +| kafka.consumer.all.fetch-latency-avg | Gauge | client-id | The average time taken for a fetch request | +| kafka.consumer.all.fetch-throttle-time-avg | Gauge | client-id | The average throttle time | +| kafka.consumer.all.records-lag-max | Gauge | client-id | Number of messages the consumer lags behind the producer | +| kafka.consumer.all.records-consumed-rate | Gauge | client-id | The average number of records consumed for all topics per second | +| kafka.consumer.all.bytes-consumed-rate | Gauge | client-id | The average number of bytes consumed for all topics per second | +| kafka.consumer.bytes-consumed-rate | Gauge | client-id, topic | The average number of bytes consumed per second | +| kafka.consumer.fetch-size-avg | Gauge | client-id, topic | The average number of bytes fetched per request | +| kafka.consumer.records-consumed-rate | Gauge | client-id, topic | The average number of records consumed per second | diff --git a/instrumentation/runtime-metrics/library/kafka-producer.md b/instrumentation/runtime-metrics/library/kafka-producer.md new file mode 100644 index 000000000000..850bc4db0cc2 --- /dev/null +++ b/instrumentation/runtime-metrics/library/kafka-producer.md @@ -0,0 +1,24 @@ +# Kafka Producer Metrics + +Here is the list of metrics based on MBeans exposed by Kafka producer.

+ +Producer metrics: + +| Metric Name | Type | Attributes | Description | +|----------------------------------------------|-------|------------------|--------------------------------------------------------------------------------------| +| kafka.producer.all.batch-size-avg | Gauge | client-id | Average number of bytes sent per partition per request | +| kafka.producer.all.bufferpool-wait-ratio | Gauge | client-id | The fraction of time an appender waits for space allocation | +| kafka.producer.all.compression-rate-avg | Gauge | client-id | Average ratio of the compressed batch size to the uncompressed size | +| kafka.producer.all.io-wait-time-ns-avg | Gauge | client-id | The average time the I/O thread spent waiting for a socket ready for reads or writes | +| kafka.producer.all.outgoing-byte-rate | Gauge | client-id | The average number of outgoing bytes sent per second to all servers | +| kafka.producer.all.produce-throttle-time-avg | Gauge | client-id | Average time a request was throttled by a broker | +| kafka.producer.all.record-queue-time-avg | Gauge | client-id | The average time record batches spent in the send buffer | +| kafka.producer.all.record-retry-rate | Gauge | client-id | The average number of retried record sends per second | +| kafka.producer.all.request-latency-avg | Gauge | client-id | The average request latency | +| kafka.producer.all.request-rate | Gauge | client-id | The average number of requests sent per second | +| kafka.producer.all.response-rate | Gauge | client-id | The average number of response sent per second | +| kafka.producer.byte-rate | Gauge | client-id, topic | The average number of bytes sent per second for a topic | +| kafka.producer.compression-rate | Gauge | client-id, topic | The average compression rate of record batches for a topic | +| kafka.producer.record-error-rate | Gauge | client-id, topic | The average per-second number of record sends that resulted in errors for a topic | +| kafka.producer.record-retry-rate | Gauge | client-id, topic | The average per-second number of retried record sends for a topic | +| kafka.producer.record-send-rate | Gauge | client-id, topic | The average number of records sent per second for a topic | diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeInfo.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeInfo.java new file mode 100644 index 000000000000..71a2020dc58a --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeInfo.java @@ -0,0 +1,53 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +/** + * A class holding relevant information about an MBean atribute which will be used for collecting + * metric values. The info comes directly from the relevant MBeans. + */ +class AttributeInfo { + + private boolean usesDoubles; + private String description; + + AttributeInfo(Number sampleValue, String description) { + if (sampleValue instanceof Byte + || sampleValue instanceof Short + || sampleValue instanceof Integer + || sampleValue instanceof Long) { + // will use Long values + usesDoubles = false; + } else { + usesDoubles = true; + } + this.description = description; + } + + boolean usesDoubleValues() { + return usesDoubles; + } + + String getDescription() { + return description; + } + + /** + * It is unlikely, but possible, that among the MBeans matching some ObjectName pattern, + * attributes with the same name but different types exist. In such cases we have to use a metric + * type which will be able to handle all of these attributes. + * + * @param other another AttributeInfo apparently for the same MBean attribute, must not be null + */ + void updateFrom(AttributeInfo other) { + if (other.usesDoubleValues()) { + usesDoubles = true; + } + if (description == null) { + description = other.getDescription(); + } + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeValueExtractor.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeValueExtractor.java new file mode 100644 index 000000000000..d526d8d634e7 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeValueExtractor.java @@ -0,0 +1,227 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.INFO; + +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; + +/** + * A class responsible for extracting attribute values from MBeans. Objects of this class are + * immutable. + */ +public class AttributeValueExtractor implements LabelExtractor { + // The attribute name to be used during value extraction from MBean + private final String baseName; + + // In case when the extracted attribute is a CompositeData value, + // how to proceed to arrive at a usable elementary value + private final String[] nameChain; + + /** + * Verify the attribute name and create a corresponding extractor object. + * + * @param rawName the attribute name, can be a reference to composite values + * @return the corresponding LabelValueExtractor + * @throws IllegalArgumentException if the attribute name is malformed + */ + public static AttributeValueExtractor fromName(String rawName) { + // Check if a CompositeType value is expected + int k = rawName.indexOf('.'); + if (k < 0) { + if (rawName.isEmpty()) { + throw new IllegalArgumentException("Empty attribute name"); + } + return new AttributeValueExtractor(rawName); + } + + // Set up extraction from CompositeType values + String baseName = rawName.substring(0, k).trim(); + String[] components = rawName.substring(k + 1).split("\\."); + + // sanity check + if (baseName.isEmpty()) { + throw new IllegalArgumentException("Invalid attribute name '" + rawName + "'"); + } + for (int j = 0; j < components.length; ++j) { + components[j] = components[j].trim(); + if (components[j].isEmpty()) { + throw new IllegalArgumentException("Invalid attribute name '" + rawName + "'"); + } + } + return new AttributeValueExtractor(baseName, components); + } + + public AttributeValueExtractor(String baseName, String... nameChain) { + if (baseName == null || nameChain == null) { + throw new IllegalArgumentException("null argument for AttributeValueExtractor"); + } + this.baseName = baseName; + this.nameChain = nameChain; + } + + /** Get a human readable name of the attribute to extract. Useful for logging or debugging. */ + String getAttributeName() { + if (nameChain.length > 0) { + StringBuilder builder = new StringBuilder(baseName); + for (String component : nameChain) { + builder.append(".").append(component); + } + return builder.toString(); + } else { + return baseName; + } + } + + /** + * Verify that the MBean identified by the given ObjectName recognizes the configured attribute, + * including the internals of CompositeData and TabularData, if applicable, and that the provided + * values will be numerical. + * + * @param server the MBeanServer that reported knowledge of the ObjectName + * @param objectName the ObjectName identifying the MBean + * @return AttributeInfo if the attribute is properly recognized, or null + */ + AttributeInfo getAttributeInfo(MBeanServer server, ObjectName objectName) { + if (MetricService.logger.isLoggable(FINE)) { + MetricService.logger.log( + FINE, "Resolving {0} for {1}", new Object[] {getAttributeName(), objectName}); + } + + try { + MBeanInfo info = server.getMBeanInfo(objectName); + MBeanAttributeInfo[] allAttributes = info.getAttributes(); + + for (MBeanAttributeInfo attr : allAttributes) { + if (baseName.equals(attr.getName())) { + String description = attr.getDescription(); + + // Verify correctness of configuration by attempting to extract the metric value. + // The value will be discarded, but its type will be checked. + Object sampleValue = extractAttributeValue(server, objectName); + + // Only numbers can be used to generate metric values + if (sampleValue instanceof Number) { + return new AttributeInfo((Number) sampleValue, description); + } else { + // It is fairly normal to get null values, especially during startup, + // but it is much more suspicious to get non-numbers + Level logLevel = sampleValue == null ? FINE : INFO; + if (MetricService.logger.isLoggable(logLevel)) { + MetricService.logger.log( + logLevel, + "Unusable value {0} for attribute {1} and ObjectName {2}", + new Object[] { + sampleValue == null ? "NULL" : sampleValue.getClass().getName(), + getAttributeName(), + objectName + }); + } + return null; + } + } + } + + if (MetricService.logger.isLoggable(FINE)) { + MetricService.logger.log( + FINE, + "Cannot find attribute {0} for ObjectName {1}", + new Object[] {baseName, objectName}); + } + + } catch (InstanceNotFoundException e) { + // Should not happen. The ObjectName we use has been provided by the MBeanServer we use. + MetricService.logger.log(INFO, "The MBeanServer does not find {0}", objectName); + } catch (Exception e) { + MetricService.logger.log( + FINE, + "Exception {0} while inspecting attributes for ObjectName {1}", + new Object[] {e, objectName}); + } + return null; + } + + /** + * Extracts the specified attribute value. In case the value is a CompositeData, drills down into + * it to find the correct singleton value (usually a Number or a String). + * + * @param server the MBeanServer to use + * @param objectName the ObjectName specifying the MBean to use, it should not be a pattern + * @param logger the logger to use, may be null + * @return the attribute value, if found, or null if an error occurred + */ + private Object extractAttributeValue(MBeanServer server, ObjectName objectName, Logger logger) { + try { + Object value = server.getAttribute(objectName, baseName); + + int k = 0; + while (k < nameChain.length) { + if (value instanceof CompositeData) { + value = ((CompositeData) value).get(nameChain[k]); + } else if (value instanceof TabularData) { + value = ((TabularData) value).get(new String[] {nameChain[k]}); + } else { + if (logger != null) { + logger.log( + FINE, + "Encountered a value of {0} while extracting attribute {1} for ObjectName {2}; unable to extract metric value", + new Object[] { + (value == null ? "NULL" : value.getClass().getName()), + getAttributeName(), + objectName + }); + } + break; + } + k++; + } + return value; + } catch (Exception e) { + // We do not really care about the actual reason for failure + if (logger != null) { + logger.log( + FINE, + "Encountered {0} while extracting attribute {1} for ObjectName {2}; unable to extract metric value", + new Object[] {e, getAttributeName(), objectName}); + } + } + return null; + } + + private Object extractAttributeValue(MBeanServer server, ObjectName objectName) { + return extractAttributeValue(server, objectName, null); + } + + Number extractNumericalAttribute(MBeanServer server, ObjectName objectName) { + Object value = extractAttributeValue(server, objectName); + if (value instanceof Number) { + return (Number) value; + } + return null; + } + + @Override + public String extractValue(MBeanServer server, ObjectName objectName) { + return extractStringAttribute(server, objectName); + } + + private String extractStringAttribute(MBeanServer server, ObjectName objectName) { + Object value = extractAttributeValue(server, objectName); + if (value instanceof String) { + return (String) value; + } + return null; + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanFinder.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanFinder.java new file mode 100644 index 000000000000..d0f769a0efe0 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanFinder.java @@ -0,0 +1,130 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectName; + +/** + * A class responsible for finding MBeans that match metric definitions specified by a set of + * MetricDefs. + */ +class BeanFinder { + + private final MetricRegistrar registrar; + private MetricConfiguration conf; + private final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); + private final long exportInterval; + private final long maxDelay; + private long delay = 1000; // number of milliseconds until first attempt to discover MBeans + + BeanFinder(MetricRegistrar registrar, ConfigProperties configProperties) { + this.registrar = registrar; + this.exportInterval = configProperties.getLong("otel.metric.export.interval", 60000); + this.maxDelay = Math.max(60000, exportInterval); + } + + void discoverBeans(MetricConfiguration conf) { + this.conf = conf; + + exec.schedule( + new Runnable() { + @Override + public void run() { + refreshState(); + delay = Math.min(delay + exportInterval, maxDelay); + exec.schedule(this, delay, TimeUnit.MILLISECONDS); + } + }, + delay, + TimeUnit.MILLISECONDS); + } + + /** + * Go over all configured metric definitions and try to find matching MBeans. Once a match is + * found for a given metric definition, submit the definition to MetricRegistrar for further + * handling. Successive invocations of this method may find matches that were previously + * unavailable, in such cases MetricRegistrar will extend the coverage for the new MBeans + */ + private void refreshState() { + List servers = MBeanServerFactory.findMBeanServer(null); + + for (MetricDef metricDef : conf.getMetricDefs()) { + resolveBeans(metricDef, servers); + } + } + + /** + * Go over the specified list of MBeanServers and try to find any MBeans matching the specified + * MetricDef. If found, verify that the MBeans support the specified attributes, and set up + * collection of corresponding metrics. + * + * @param metricDef the MetricDef used to find matching MBeans + * @param servers the list of MBeanServers to query + */ + private void resolveBeans(MetricDef metricDef, List servers) { + BeanPack beans = metricDef.getBeanPack(); + + for (MBeanServer server : servers) { + // The set of all matching ObjectNames recognized by the server + Set allObjectNames = new HashSet<>(); + + for (ObjectName pattern : beans.getNamePatterns()) { + Set objectNames = server.queryNames(pattern, beans.getQueryExp()); + allObjectNames.addAll(objectNames); + } + + if (!allObjectNames.isEmpty()) { + resolveAttributes(allObjectNames, server, metricDef); + + // Assuming that only one MBeanServer has the required MBeans + break; + } + } + } + + /** + * Go over the collection of matching MBeans and try to find all matching attributes. For every + * successful match, activate metric value collection. + * + * @param objectNames the collection of ObjectNames identifying the MBeans + * @param server the MBeanServer which recognized the collection of ObjectNames + * @param metricDef the MetricDef describing the attributes to look for + */ + private void resolveAttributes( + Set objectNames, MBeanServer server, MetricDef metricDef) { + for (MetricExtractor extractor : metricDef.getMetricExtractors()) { + // For each MetricExtractor, find the subset of MBeans that have the required attribute + List validObjectNames = new ArrayList<>(); + AttributeInfo attributeInfo = null; + for (ObjectName objectName : objectNames) { + AttributeInfo attr = + extractor.getMetricValueExtractor().getAttributeInfo(server, objectName); + if (attr != null) { + if (attributeInfo == null) { + attributeInfo = attr; + } else { + attributeInfo.updateFrom(attr); + } + validObjectNames.add(objectName); + } + } + if (!validObjectNames.isEmpty()) { + // Ready to collect metric values + registrar.enrollExtractor(server, validObjectNames, extractor, attributeInfo); + } + } + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanPack.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanPack.java new file mode 100644 index 000000000000..3bbd7d03c1a9 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanPack.java @@ -0,0 +1,39 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +import javax.management.ObjectName; +import javax.management.QueryExp; + +/** + * A class describing a set of MBeans which can be used to collect values for a metric. Objects of + * this class are inmutable. + */ +public class BeanPack { + // How to specify the MBean(s) + private final QueryExp queryExp; + private final ObjectName[] namePatterns; + + /** + * Constructor for BeanPack. + * + * @param queryExp the QueryExp to be used to filter results when looking for MBeans + * @param namePatterns an array of ObjectNames used to look for MBeans; usually they will be + * patterns. If multiple patterns are provided, they work as logical OR. + */ + public BeanPack(QueryExp queryExp, ObjectName... namePatterns) { + this.queryExp = queryExp; + this.namePatterns = namePatterns; + } + + QueryExp getQueryExp() { + return queryExp; + } + + ObjectName[] getNamePatterns() { + return namePatterns; + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/DetectionStatus.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/DetectionStatus.java new file mode 100644 index 000000000000..40a78a440b00 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/DetectionStatus.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +import java.util.Collection; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +/** + * A class encapsulating a set of ObjectNames and the MBeanServer that recognized them. Objects of + * this class are inmutable. + */ +class DetectionStatus { + + private final MBeanServer server; + private final Collection objectNames; + + DetectionStatus(MBeanServer server, Collection objectNames) { + this.server = server; + this.objectNames = objectNames; + } + + MBeanServer getServer() { + return server; + } + + Collection getObjectNames() { + return objectNames; + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/LabelExtractor.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/LabelExtractor.java new file mode 100644 index 000000000000..967573fa42bd --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/LabelExtractor.java @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +/** + * LabelExtractors are responsible for obtaining values for populating Labels, i.e. Measurement + * attributes. + */ +public interface LabelExtractor { + + String extractValue(MBeanServer server, ObjectName objectName); +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricBanner.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricBanner.java new file mode 100644 index 000000000000..2c74088729da --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricBanner.java @@ -0,0 +1,59 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +/** + * A class providing the user visible characteristics (name, type, description and units) of a + * metric to be reported with OpenTelemetry. + * + *

Objects of this class are inmutable. + */ +public class MetricBanner { + + // OpenTelemetry asynchronous instrument types that can be used + public enum Type { + COUNTER, + UPDOWNCOUNTER, + GAUGE + } + + // How to report the metric using OpenTelemetry API + private final String metricName; // used as Instrument name + private final String description; + private final String unit; + private final Type type; + + /** + * Constructor for MetricBanner. + * + * @param metricName a String that will be used as a metric name, it should be unique + * @param description a human readable description of the metric + * @param unit a human readable unit of measurement + * @param type the instrument typ to be used for the metric + */ + public MetricBanner(String metricName, String description, String unit, Type type) { + this.metricName = metricName; + this.description = description; + this.unit = unit; + this.type = type == null ? Type.GAUGE : type; + } + + String getMetricName() { + return metricName; + } + + String getDescription() { + return description; + } + + String getUnit() { + return unit; + } + + Type getType() { + return type; + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricConfiguration.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricConfiguration.java new file mode 100644 index 000000000000..f1c8c8afc2f6 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricConfiguration.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * A class responsible for maintaining the current configuration for JMX metrics to be collected. + */ +public class MetricConfiguration { + + private final Collection currentSet = new ArrayList<>(); + + public MetricConfiguration() {} + + public boolean isEmpty() { + return currentSet.isEmpty(); + } + + public void addMetricDef(MetricDef def) { + currentSet.add(def); + } + + Collection getMetricDefs() { + return currentSet; + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricDef.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricDef.java new file mode 100644 index 000000000000..1380deb32576 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricDef.java @@ -0,0 +1,50 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +/** + * A class providing a complete definition on how to create an Open Telemetry metric out of the JMX + * system: how to extract values from MBeans and how to model, name and label them using + * OpenTelemetry Metric API. Objects of this class are inmutable. + * + *

Example: The JVM provides an MBean with ObjectName "java.lang:type=Threading", and one of the + * MBean attributes is "ThreadCount". This MBean can be used to provide a metric showing the current + * number of threads run by the JVM as follows: + * + *

new MetricDef(new BeanPack(null, new ObjectName("java.lang:type=Threading")), + * + *

new MetricExtractor(new AttributeValueExtractor("ThreadCount"), + * + *

new MetricBanner("process.runtime.jvm.threads", "Current number of threads", "1" ))); + */ +public class MetricDef { + + // Describes the MBeans to use + private final BeanPack beans; + + // Describes how to get the metric values and their labels (dimensions), and how to report them + private final MetricExtractor[] metricExtractors; + + /** + * Constructor for MetricDef. + * + * @param beans description of MBeans required to obtain metric values + * @param metricExtractors description of how to extract and label metric values; if more than one + * MetricExtractor is provided, they should use unique metric names or unique labels + */ + public MetricDef(BeanPack beans, MetricExtractor... metricExtractors) { + this.beans = beans; + this.metricExtractors = metricExtractors; + } + + BeanPack getBeanPack() { + return beans; + } + + MetricExtractor[] getMetricExtractors() { + return metricExtractors; + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricExtractor.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricExtractor.java new file mode 100644 index 000000000000..70ae816e9474 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricExtractor.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +/** + * A class holding the info needed to support a single metric: how to define it in OpenTelemetry and + * how to provide the metric values. + * + *

Objects of this class are stateful, the DetectionStatus may change over time to keep track of + * all ObjectNames that should be used to deliver the metric values. + */ +public class MetricExtractor { + + private final MetricBanner banner; + + // Defines the way to access the metric value (a number) + private final AttributeValueExtractor attributeExtractor; + + // Defines the Measurement attributes to be used when reporting the metric value. + // We call them labels to avoid confusion with MBean attributes + private final MetricLabel[] labels; + + private volatile DetectionStatus status; + + public MetricExtractor( + AttributeValueExtractor attributeExtractor, MetricBanner banner, MetricLabel... labels) { + this.attributeExtractor = attributeExtractor; + this.banner = banner; + this.labels = labels; + } + + MetricBanner getBanner() { + return banner; + } + + AttributeValueExtractor getMetricValueExtractor() { + return attributeExtractor; + } + + MetricLabel[] getLabels() { + return labels; + } + + void setStatus(DetectionStatus status) { + this.status = status; + } + + DetectionStatus getStatus() { + return status; + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricLabel.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricLabel.java new file mode 100644 index 000000000000..1cce4a01eb6b --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricLabel.java @@ -0,0 +1,51 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +/** + * A class representing a metric attribute (label). It is responsible for extracting a label value + * (to be reported as a Measurement attribute), and for holding the corresponding label name to be + * used. Objects of this class are inmutable. + */ +public class MetricLabel { + private final String labelName; + private final LabelExtractor extractor; + + public MetricLabel(String labelName, LabelExtractor extractor) { + this.labelName = labelName; + this.extractor = extractor; + } + + public String getLabelName() { + return labelName; + } + + String extractLabelValue(MBeanServer server, ObjectName objectName) { + return extractor.extractValue(server, objectName); + } + + public static LabelExtractor fromConstant(String constantValue) { + return (a, b) -> { + return constantValue; + }; + } + + public static LabelExtractor fromParameter(String parameterKey) { + if (parameterKey.isEmpty()) { + throw new IllegalArgumentException("Empty parameter name"); + } + return (dummy, objectName) -> { + return objectName.getKeyProperty(parameterKey); + }; + } + + public static LabelExtractor fromAttribute(String attributeName) { + return AttributeValueExtractor.fromName(attributeName); + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricRegistrar.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricRegistrar.java new file mode 100644 index 000000000000..461839b4de75 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricRegistrar.java @@ -0,0 +1,191 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +import static java.util.logging.Level.CONFIG; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.api.metrics.DoubleGaugeBuilder; +import io.opentelemetry.api.metrics.LongCounterBuilder; +import io.opentelemetry.api.metrics.LongUpDownCounterBuilder; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; +import io.opentelemetry.api.metrics.ObservableLongMeasurement; +import java.util.Collection; +import java.util.function.Consumer; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +/** A class responsible for maintaining the set of metrics to collect and report. */ +class MetricRegistrar { + + private final Meter meter; + + MetricRegistrar(OpenTelemetry openTelemetry, String instrumentationScope) { + meter = openTelemetry.getMeter(instrumentationScope); + } + + /** + * Accepts a MetricExtractor for registration and activation. + * + * @param server the MBeanServer to use to query for metric values + * @param objectNames the Objectnames that are known to the server and that know the attribute + * that is required to get the metric values + * @param extractor the MetricExtractor responsible for getting the metric values + */ + void enrollExtractor( + MBeanServer server, + Collection objectNames, + MetricExtractor extractor, + AttributeInfo attributeInfo) { + // For the first enrollment of the extractor we have to build the corresponding Instrument + DetectionStatus status = new DetectionStatus(server, objectNames); + boolean firstEnrollment; + synchronized (extractor) { + firstEnrollment = extractor.getStatus() == null; + // For successive enrollments, it is sufficient to refresh the status + extractor.setStatus(status); + } + + if (firstEnrollment) { + MetricBanner banner = extractor.getBanner(); + String metricName = banner.getMetricName(); + MetricBanner.Type instrumentType = banner.getType(); + String description = + banner.getDescription() != null + ? banner.getDescription() + : attributeInfo.getDescription(); + String unit = banner.getUnit(); + + switch (instrumentType) { + // CHECKSTYLE:OFF + case COUNTER: + { + // CHECKSTYLE:ON + LongCounterBuilder builder = meter.counterBuilder(metricName); + if (description != null) { + builder = builder.setDescription(description); + } + if (unit != null) { + builder = builder.setUnit(unit); + } + + if (attributeInfo.usesDoubleValues()) { + builder.ofDoubles().buildWithCallback(doubleTypeCallback(extractor)); + } else { + builder.buildWithCallback(longTypeCallback(extractor)); + } + MetricService.logger.log(CONFIG, "Created Counter for {0}", metricName); + } + break; + + // CHECKSTYLE:OFF + case UPDOWNCOUNTER: + { + // CHECKSTYLE:ON + LongUpDownCounterBuilder builder = meter.upDownCounterBuilder(metricName); + if (description != null) { + builder = builder.setDescription(description); + } + if (unit != null) { + builder = builder.setUnit(unit); + } + + if (attributeInfo.usesDoubleValues()) { + builder.ofDoubles().buildWithCallback(doubleTypeCallback(extractor)); + } else { + builder.buildWithCallback(longTypeCallback(extractor)); + } + MetricService.logger.log(CONFIG, "Created UpDownCounter for {0}", metricName); + } + break; + + // CHECKSTYLE:OFF + case GAUGE: + { + // CHECKSTYLE:ON + DoubleGaugeBuilder builder = meter.gaugeBuilder(metricName); + if (description != null) { + builder = builder.setDescription(description); + } + if (unit != null) { + builder = builder.setUnit(unit); + } + + if (attributeInfo.usesDoubleValues()) { + builder.buildWithCallback(doubleTypeCallback(extractor)); + } else { + builder.ofLongs().buildWithCallback(longTypeCallback(extractor)); + } + MetricService.logger.log(CONFIG, "Created Gauge for {0}", metricName); + } + } + } + } + + /* + * A method generating metric collection callback for asynchronous Measurement + * of Double type. + */ + static Consumer doubleTypeCallback(MetricExtractor extractor) { + return measurement -> { + DetectionStatus status = extractor.getStatus(); + if (status != null) { + MBeanServer server = status.getServer(); + for (ObjectName objectName : status.getObjectNames()) { + Number metricValue = + extractor.getMetricValueExtractor().extractNumericalAttribute(server, objectName); + if (metricValue != null) { + // get the labels + Attributes attr = createLabels(server, objectName, extractor); + measurement.record(metricValue.doubleValue(), attr); + } + } + } + }; + } + + /* + * A method generating metric collection callback for asynchronous Measurement + * of Long type. + */ + static Consumer longTypeCallback(MetricExtractor extractor) { + return measurement -> { + DetectionStatus status = extractor.getStatus(); + if (status != null) { + MBeanServer server = status.getServer(); + for (ObjectName objectName : status.getObjectNames()) { + Number metricValue = + extractor.getMetricValueExtractor().extractNumericalAttribute(server, objectName); + if (metricValue != null) { + // get the labels + Attributes attr = createLabels(server, objectName, extractor); + measurement.record(metricValue.longValue(), attr); + } + } + } + }; + } + + /* + * An auxiliary method for collecting labels (Measurement attributes) to go along + * the metric values + */ + static Attributes createLabels( + MBeanServer server, ObjectName objectName, MetricExtractor extractor) { + MetricLabel[] labels = extractor.getLabels(); + AttributesBuilder attrBuilder = Attributes.builder(); + for (MetricLabel label : labels) { + String labelValue = label.extractLabelValue(server, objectName); + if (labelValue != null) { + attrBuilder = attrBuilder.put(label.getLabelName(), labelValue); + } + } + return attrBuilder.build(); + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricService.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricService.java new file mode 100644 index 000000000000..8599adc7b6ae --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricService.java @@ -0,0 +1,101 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +import static java.util.logging.Level.CONFIG; +import static java.util.logging.Level.FINE; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.yaml.RuleParser; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import java.io.File; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.logging.Logger; + +/** Collecting and exporting JMX metrics. */ +public class MetricService { + + static final Logger logger = Logger.getLogger("JMX Metric Insight"); + + private static final String INSTRUMENTATION_SCOPE = "io.opentelemetry.jmx"; + + private final OpenTelemetry openTelemetry; + private final ConfigProperties configProperties; + + public MetricService(OpenTelemetry ot, ConfigProperties config) { + openTelemetry = ot; + configProperties = config; + } + + private static String resourceFor(String platform) { + return "/jmx/rules/" + platform + ".yaml"; + } + + private void addRulesForPlatform(String platform, MetricConfiguration conf) { + + String yamlResource = resourceFor(platform); + try (InputStream inputStream = getClass().getResourceAsStream(yamlResource)) { + if (inputStream != null) { + logger.log(FINE, "Opened input stream {0}", yamlResource); + RuleParser parserInstance = RuleParser.get(); + parserInstance.addMetricDefs(logger, conf, inputStream); + } else { + logger.log(CONFIG, "No support found for {0}", platform); + } + } catch (Exception e) { + logger.warning(e.getMessage()); + } + } + + private void buildFromDefaultRules(MetricConfiguration conf) { + + String targetSystem = System.getProperty("otel.jmx.target.system", "").trim(); + String[] platforms = targetSystem.length() == 0 ? new String[0] : targetSystem.split(","); + + for (String platform : platforms) { + addRulesForPlatform(platform, conf); + } + } + + private static void buildFromUserRules(MetricConfiguration conf) { + String jmxDir = System.getProperty("otel.jmx.config"); + if (jmxDir != null) { + logger.log(CONFIG, "JMX config file name: {0}", jmxDir); + RuleParser parserInstance = RuleParser.get(); + try (InputStream inputStream = Files.newInputStream(new File(jmxDir.trim()).toPath())) { + parserInstance.addMetricDefs(logger, conf, inputStream); + } catch (Exception e) { + logger.warning(e.getMessage()); + } + } + } + + private MetricConfiguration buildMetricConfiguration() { + MetricConfiguration conf = new MetricConfiguration(); + + buildFromDefaultRules(conf); + + buildFromUserRules(conf); + + return conf; + } + + public void start() { + MetricConfiguration conf = buildMetricConfiguration(); + + if (conf.isEmpty()) { + logger.log( + CONFIG, + "Empty JMX configuration, no metrics will be collected for InstrumentationScope " + + INSTRUMENTATION_SCOPE); + } else { + MetricRegistrar registrar = new MetricRegistrar(openTelemetry, INSTRUMENTATION_SCOPE); + BeanFinder finder = new BeanFinder(registrar, configProperties); + finder.discoverBeans(conf); + } + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxConfig.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxConfig.java new file mode 100644 index 000000000000..f79f9d02a609 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxConfig.java @@ -0,0 +1,46 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data; + +import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricConfiguration; +import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricDef; +import java.util.List; + +/** + * JMX configuration as a set of JMX rules. Objects of this class are created and populated by the + * YAML parser. + */ +public class JmxConfig { + + // Used by the YAML parser + // rules: + // - JMX_DEFINITION1 + // - JMX_DEFINITION2 + // The parser is guaranteed to call setRules with a non-null argument, or throw an exception + private List rules; + + public List getRules() { + return rules; + } + + public void setRules(List rules) { + this.rules = rules; + } + + /** + * Converts the rules from this object into MetricDefs and adds them to the specified + * MetricConfiguration. + * + * @param configuration MetricConfiguration to add MetricDefs to + * @throws an exception if the rule conversion cannot be performed + */ + public void addMetricDefs(MetricConfiguration configuration) throws Exception { + for (JmxRule rule : rules) { + MetricDef metricDef = rule.buildMetricDef(); + configuration.addMetricDef(metricDef); + } + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxRule.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxRule.java new file mode 100644 index 000000000000..a18694c584ed --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxRule.java @@ -0,0 +1,195 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data; + +import io.opentelemetry.instrumentation.runtimemetrics.jmx.AttributeValueExtractor; +import io.opentelemetry.instrumentation.runtimemetrics.jmx.BeanPack; +import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricBanner; +import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricDef; +import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricExtractor; +import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricLabel; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +/** + * This class represents a complete JMX metrics rule as defined by a YAML file. Objects of this + * class are created and populated by the YAML parser. + */ +public class JmxRule extends MetricStructure { + + // Used by the YAML parser + // bean: OBJECT_NAME + // beans: + // - OBJECTNAME1 + // - OBJECTNAME2 + // prefix: METRIC_NAME_PREFIX + // mapping: + // ATTRIBUTE1: + // METRIC_FIELDS1 + // ATTRIBUTE2: + // ATTRIBUTE3: + // METRIC_FIELDS3 + // The parser never calls setters for these fields with null arguments + private String bean; + private List beans; + private String prefix; + private Map mapping; + + public String getBean() { + return bean; + } + + public void setBean(String bean) throws Exception { + this.bean = validateBean(bean); + } + + public List getBeans() { + return beans; + } + + private static String validateBean(String name) throws MalformedObjectNameException { + String trimmed = name.trim(); + // Check the syntax of the provided name by attempting to create an ObjectName from it. + new ObjectName(trimmed); + return trimmed; + } + + public void setBeans(List beans) throws Exception { + List list = new ArrayList<>(); + for (String name : beans) { + list.add(validateBean(name)); + } + this.beans = list; + } + + public void setPrefix(String prefix) { + this.prefix = validatePrefix(prefix.trim()); + } + + private String validatePrefix(String prefix) { + // Do not accept empty string. + // While it is theoretically acceptable, it probably indicates a user error. + requireNonEmpty(prefix, "The metric name prefix is empty"); + return prefix; + } + + public String getPrefix() { + return prefix; + } + + public Map getMapping() { + return mapping; + } + + public void setMapping(Map mapping) { + this.mapping = validateAttributeMapping(mapping); + } + + private static Map validateAttributeMapping(Map mapping) { + + if (mapping.isEmpty()) { + throw new IllegalStateException("No MBean attributes specified"); + } + // Make sure that all attribute names are well-formed by creating the corresponding + // AttributeValueExtractors + Set attrNames = mapping.keySet(); + for (String attributeName : attrNames) { + // check if AttributeValueExtractors can be built without exceptions + AttributeValueExtractor.fromName(attributeName); + } + return mapping; + } + + /** + * Convert this rule to a complete MetricDefinition object. If the rule is incomplete or has + * consistency or semantic issues, an exception will be thrown. + * + * @return a valid MetricDefinition object + * @throws an exception if any issues within the rule are detected + */ + public MetricDef buildMetricDef() throws Exception { + BeanPack pack; + if (bean != null) { + pack = new BeanPack(null, new ObjectName(bean)); + } else if (beans != null && !beans.isEmpty()) { + ObjectName[] objectNames = new ObjectName[beans.size()]; + int k = 0; + for (String oneBean : beans) { + objectNames[k++] = new ObjectName(oneBean); + } + pack = new BeanPack(null, objectNames); + } else { + throw new IllegalStateException("No ObjectName specified"); + } + + if (mapping == null || mapping.isEmpty()) { + throw new IllegalStateException("No MBean attributes specified"); + } + + Set attrNames = mapping.keySet(); + MetricExtractor[] metricExtractors = new MetricExtractor[attrNames.size()]; + int n = 0; + for (String attributeName : attrNames) { + MetricBanner banner; + Metric m = mapping.get(attributeName); + if (m == null) { + banner = + new MetricBanner( + prefix == null ? attributeName : (prefix + attributeName), + null, + getUnit(), + getMetricType()); + } else { + banner = m.buildMetricBanner(prefix, attributeName, getUnit(), getMetricType()); + } + AttributeValueExtractor attrExtractor = AttributeValueExtractor.fromName(attributeName); + + List labelList; + List ownLabels = getLabels(); + if (ownLabels != null && m != null && m.getLabels() != null) { + // MetricLabels have been specified at two levels, need to combine them + labelList = combineLabels(ownLabels, m.getLabels()); + } else if (ownLabels != null) { + labelList = ownLabels; + } else if (m != null && m.getLabels() != null) { + // Get the labels from the metric + labelList = m.getLabels(); + } else { + // There are no labels at all + labelList = new ArrayList(); + } + + MetricExtractor metricExtractor = + new MetricExtractor( + attrExtractor, banner, labelList.toArray(new MetricLabel[labelList.size()])); + metricExtractors[n++] = metricExtractor; + } + + return new MetricDef(pack, metricExtractors); + } + + private static List combineLabels( + List ownLabels, List metricLabels) { + Map set = new HashMap<>(); + for (MetricLabel ownLabel : ownLabels) { + set.put(ownLabel.getLabelName(), ownLabel); + } + + // Let the metric level defined labels override own lables + for (MetricLabel metricLabel : metricLabels) { + set.put(metricLabel.getLabelName(), metricLabel); + } + + List result = new ArrayList(); + result.addAll(set.values()); + return result; + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/Metric.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/Metric.java new file mode 100644 index 000000000000..10bdcdec0098 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/Metric.java @@ -0,0 +1,66 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data; + +import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricBanner; + +/** + * A class representing metric definition as a part of YAML metric rule. Objects of this class are + * created and populated by the YAML parser. + */ +public class Metric extends MetricStructure { + + // Used by the YAML parser + // metric: METRIC_NAME + // desc: DESCRIPTION + // The parser never calls setters for these fields with null arguments + private String metric; + private String desc; + + public String getMetric() { + return metric; + } + + public void setMetric(String metric) { + this.metric = validateMetricName(metric.trim()); + } + + private String validateMetricName(String name) { + requireNonEmpty(name, "The metric name is empty"); + return name; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + // No constraints on description + this.desc = desc.trim(); + } + + MetricBanner buildMetricBanner( + String prefix, String attributeName, String defaultUnit, MetricBanner.Type defaultType) { + String metricName; + if (metric == null) { + metricName = prefix == null ? attributeName : (prefix + attributeName); + } else { + metricName = prefix == null ? metric : (prefix + metric); + } + + MetricBanner.Type metricType = getMetricType(); + if (metricType == null) { + metricType = defaultType; + } + + String unit = getUnit(); + if (unit == null) { + unit = defaultUnit; + } + + return new MetricBanner(metricName, desc, unit, metricType); + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/MetricStructure.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/MetricStructure.java new file mode 100644 index 000000000000..c546d90a3a14 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/MetricStructure.java @@ -0,0 +1,130 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data; + +import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricBanner; +import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricLabel; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * An abstract class containing skeletal info about Metrics: + *

  • the metric type + *
  • the metric attributes (labels) + *
  • the unit + * + *

    Known subclasses are JMXRule and Metric. + */ +abstract class MetricStructure { + + // Used by the YAML parser + // type: TYPE + // label: + // KEY1: SPECIFICATION1 + // KEY2: SPECIFICATION2 + // unit: UNIT + + private String type; // unused, for YAML parser only + private Map label; // unused, for YAML parser only + private String unit; + + private MetricBanner.Type metricType; + private List labels; + + public String getType() { + return type; + } + + public void setType(String t) { + // Do not complain about case variations + t = t.trim().toUpperCase(); + this.metricType = MetricBanner.Type.valueOf(t); + this.type = t; + } + + public String getUnit() { + return unit; + } + + public void setUnit(String unit) { + this.unit = validateUnit(unit.trim()); + } + + private String validateUnit(String unit) { + requireNonEmpty(unit, "Metric unit is empty"); + return unit; + } + + /** + * When the YAML parser sets the labels, convert them immediately to MetricLabels. Any errors + * during conversion will show in the context of the parsed YAML file. + * + * @param label the mapping of metric attribute keys to evaluating snippets + */ + public void setLabel(Map label) { + this.label = label; + // pre-build the Labels + List labelList = new ArrayList<>(); + addLabels(labelList, label); + this.labels = labelList; + } + + // Used only for testing + public Map getLabel() { + return label; + } + + public MetricBanner.Type getMetricType() { + return metricType; + } + + protected List getLabels() { + return labels; + } + + protected void requireNonEmpty(String s, String msg) { + if (s.isEmpty()) { + throw new IllegalArgumentException(msg); + } + } + + private static void addLabels(List list, Map tagMap) { + if (tagMap != null) { + for (String key : tagMap.keySet()) { + String target = tagMap.get(key); + if (target == null) { + throw new IllegalStateException("nothing specified for label key '" + key + "'"); + } + list.add(buildLabel(key, target.trim())); + } + } + } + + private static MetricLabel buildLabel(String key, String target) { + // The recognized forms of target are: + // - param(STRING) + // - attrib(STRING) + // - STRING + // where STRING is the name of the corresponding parameter key, attribute name, + // or the direct value to use + int k = target.indexOf(')'); + + // Check for one of the cases as above + if (target.startsWith("param(")) { + if (k > 0) { + return new MetricLabel(key, MetricLabel.fromParameter(target.substring(6, k).trim())); + } + } else if (target.startsWith("attrib(")) { + if (k > 0) { + return new MetricLabel(key, MetricLabel.fromAttribute(target.substring(7, k).trim())); + } + } else if (k < 0) { + return new MetricLabel(key, MetricLabel.fromConstant(target)); + } + throw new IllegalArgumentException("Invalid label specification for '" + key + "'"); + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/yaml/RuleParser.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/yaml/RuleParser.java new file mode 100644 index 000000000000..7ccd418b2de9 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/yaml/RuleParser.java @@ -0,0 +1,90 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.yaml; + +import static java.util.logging.Level.CONFIG; +import static java.util.logging.Level.WARNING; + +import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricConfiguration; +import io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data.JmxConfig; +import java.io.InputStream; +import java.util.logging.Logger; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; + +/** Parse a YAML file containing a number of rules. */ +public class RuleParser { + + // The YAML parser will create and populate objects of the following classes from the + // io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data package: + // - JmxConfig + // - JmxRule (a subclass of MetricStructure) + // - Metric (a subclass of MetricStructure) + // To populate the objects, the parser will call setter methods for the object fields with + // whatever comes as the result of parsing the YAML file. This means that the arguments for + // the setter calls will be non-null, unless the user will explicitly specify the 'null' literal. + // However, there's hardly any difference in user visible error messages whether the setter + // throws an IllegalArgumentException, or NullPointerException. Therefore, in all above + // classes we skip explicit checks for nullnes in the field setters, and let the setters + // crash with NullPointerException instead. + + private static RuleParser theParser = null; + + public static RuleParser get() { + if (theParser == null) { + theParser = new RuleParser(); + } + return theParser; + } + + private RuleParser() {} + + public JmxConfig loadConfig(InputStream is) throws Exception { + Yaml yaml = new Yaml(new Constructor(JmxConfig.class)); + return yaml.load(is); + } + + /** + * Parse the YAML rules from the specified input stream and add them, after converting to the + * internal representation, to the provided metric configuration. + * + * @param logger logger to be used for any messages + * @param conf the metric configuration + * @param is the InputStream with the YAML rules + */ + public void addMetricDefs(Logger logger, MetricConfiguration conf, InputStream is) { + try { + + JmxConfig config = loadConfig(is); + if (config != null) { + logger.log(CONFIG, "Found {0} metric rules", config.getRules().size()); + config.addMetricDefs(conf); + } + } catch (Exception exception) { + logger.log(WARNING, "Failed to parse YAML rules: " + rootCause(exception)); + // It is essential that the parser exception is made visible to the user. + // It contains contextual information about any syntax issues found by the parser. + logger.log(WARNING, exception.toString()); + } + } + + /** + * Given an exception thrown by the parser, try to find the original cause of the problem. + * + * @param exception the exception thrown by the parser + * @return a String describing the probable root cause + */ + private static String rootCause(Throwable exception) { + String rootClass = ""; + String message = null; + // Go to the bottom of it + for (; exception != null; exception = exception.getCause()) { + rootClass = exception.getClass().getSimpleName(); + message = exception.getMessage(); + } + return message == null ? rootClass : message; + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/activemq.yaml b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/activemq.yaml new file mode 100644 index 000000000000..16711fd3a13d --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/activemq.yaml @@ -0,0 +1,66 @@ +--- +rules: + + - beans: + - org.apache.activemq:type=Broker,brokerName=*,destinationType=Queue,destinationName=* + - org.apache.activemq:type=Broker,brokerName=*,destinationType=Topic,destinationName=* + label: + destination: param(destinationName) + broker: param(brokerName) + prefix: activemq. + mapping: + ProducerCount: + unit: '{producers}' + type: updowncounter + desc: The number of producers attached to this destination + ConsumerCount: + unit: '{consumers}' + type: updowncounter + desc: The number of consumers subscribed to this destination + MemoryPercentUsage: + metric: memory.MemoryPercentUsage + unit: '%' + type: gauge + desc: The percentage of configured memory used + QueueSize: + metric: message.QueueSize + unit: '{messages}' + type: updowncounter + desc: The current number of messages waiting to be consumed + ExpiredCount: + metric: message.ExpiredCount + unit: '{messages}' + type: counter + desc: The number of messages not delivered because they expired + EnqueueCount: + metric: message.EnqueueCount + unit: '{messages}' + type: counter + desc: The number of messages sent to this destination + DequeueCount: + metric: message.DequeueCount + unit: '{messages}' + type: counter + desc: The number of messages acknowledged and removed from this destination + AverageEnqueueTime: + metric: message.AverageEnqueueTime + unit: ms + type: gauge + desc: The average time a message was held on this destination + + - bean: org.apache.activemq:type=Broker,brokerName=* + prefix: activemq. + unit: '%' + type: gauge + mapping: + CurrentConnectionsCount: + metric: connections.CurrentConnectionsCount + type: updowncounter + unit: '{connections}' + desc: The total number of current connections + StorePercentUsage: + metric: disc.StorePercentUsage + desc: The percentage of configured disk used for persistent messages + TempPercentUsage: + metric: disc.TempPercentUsage + desc: The percentage of configured disk used for non-persistent messages \ No newline at end of file diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/hadoop.yaml b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/hadoop.yaml new file mode 100644 index 000000000000..ae35a40a3ed0 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/hadoop.yaml @@ -0,0 +1,63 @@ +--- +rules: + - bean: Hadoop:service=NameNode,name=FSNamesystem + unit: 1 + prefix: hadoop. + label: + node_name: param(tag.Hostname) + mapping: + CapacityUsed: + metric: capacity.CapacityUsed + type: updowncounter + unit: By + desc: Current used capacity across all data nodes + CapacityTotal: + metric: capacity.CapacityTotal + type: updowncounter + unit: By + BlocksTotal: + metric: block.BlocksTotal + type: updowncounter + unit: '{blocks}' + desc: Current number of allocated blocks in the system + MissingBlocks: + metric: block.MissingBlocks + type: updowncounter + unit: '{blocks}' + desc: Current number of missing blocks + CorruptBlocks: + metric: block.CorruptBlocks + type: updowncounter + unit: '{blocks}' + desc: Current number of blocks with corrupt replicas + VolumeFailuresTotal: + metric: volume.VolumeFailuresTotal + type: updowncounter + unit: '{volumes}' + desc: Total number of volume failures across all data nodes + label: + direction: sent + FilesTotal: + metric: file.FilesTotal + type: updowncounter + unit: '{files}' + desc: Current number of files and directories + TotalLoad: + metric: file.TotalLoad + type: updowncounter + unit: '{operations}' + desc: Current number of connections + NumLiveDataNodes: + metric: datenode.Count + type: updowncounter + unit: '{nodes}' + desc: The Number of data nodes + label: + state: live + NumDeadDataNodes: + metric: datenode.Count + type: updowncounter + unit: '{nodes}' + desc: The Number of data nodes + label: + state: dead diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/jetty.yaml new file mode 100644 index 000000000000..d387a2d16a8e --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/jetty.yaml @@ -0,0 +1,54 @@ +--- +rules: + + - bean: org.eclipse.jetty.server.session:context=*,type=sessionhandler,id=* + unit: s + prefix: jetty.session. + type: updowncounter + label: + resource: param(context) + mapping: + sessionsCreated: + unit: '{sessions}' + type: counter + desc: The number of sessions established in total + sessionTimeTotal: + desc: The total time sessions have been active + sessionTimeMax: + desc: The maximum amount of time a session has been active + sessionTimeMean: + type: gauge + desc: The mean time sessions remain active + + - bean: org.eclipse.jetty.util.thread:type=queuedthreadpool,id=* + prefix: jetty.threads. + unit: '{threads}' + type: updowncounter + mapping: + busyThreads: + desc: The current number of busy threads + idleThreads: + desc: The current number of idle threads + maxThreads: + desc: The maximum number of threads in the pool + queueSize: + desc: The current number of threads in the queue + + - bean: org.eclipse.jetty.io:context=*,type=managedselector,id=* + prefix: jetty.io. + label: + resource: param(context) + id: param(id) + mapping: + selectCount: + type: counter + unit: 1 + desc: The number of select calls + + - bean: org.eclipse.jetty.logging:type=jettyloggerfactory,id=* + prefix: jetty.logging. + mapping: + LoggerCount: + type: updowncounter + unit: 1 + desc: The number of registered loggers by name \ No newline at end of file diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-broker.yaml b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-broker.yaml new file mode 100644 index 000000000000..584c90d2db29 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-broker.yaml @@ -0,0 +1,205 @@ +--- +rules: + # Broker metrics + + - bean: kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec + mapping: + Count: + metric: kafka.message.count + type: counter + desc: The number of messages received by the broker + unit: '{messages}' + + - bean: kafka.server:type=BrokerTopicMetrics,name=TotalFetchRequestsPerSec + label: + type: fetch + mapping: + Count: + metric: kafka.request.count + type: counter + desc: The number of requests received by the broker + unit: '{requests}' + + - bean: kafka.server:type=BrokerTopicMetrics,name=TotalProduceRequestsPerSec + label: + type: produce + mapping: + Count: + metric: kafka.request.count + type: counter + desc: The number of requests received by the broker + unit: '{requests}' + + - bean: kafka.server:type=BrokerTopicMetrics,name=FailedFetchRequestsPerSec + label: + type: fetch + mapping: + Count: + metric: kafka.request.failed + type: counter + desc: The number of requests to the broker resulting in a failure + unit: '{requests}' + + - bean: kafka.server:type=BrokerTopicMetrics,name=FailedProduceRequestsPerSec + label: + type: produce + mapping: + Count: + metric: kafka.request.failed + type: counter + desc: The number of requests to the broker resulting in a failure + unit: '{requests}' + + - beans: + - kafka.network:type=RequestMetrics,name=TotalTimeMs,request=Produce + - kafka.network:type=RequestMetrics,name=TotalTimeMs,request=FetchConsumer + - kafka.network:type=RequestMetrics,name=TotalTimeMs,request=FetchFollower + label: + type: param(request) + unit: ms + mapping: + Count: + metric: kafka.request.time.total + type: counter + desc: The total time the broker has taken to service requests + 50thPercentile: + metric: kafka.request.time.50p + type: gauge + desc: The 50th percentile time the broker has taken to service requests + 99thPercentile: + metric: kafka.request.time.99p + type: gauge + desc: The 99th percentile time the broker has taken to service requests + + - bean: kafka.network:type=RequestChannel,name=RequestQueueSize + mapping: + Value: + metric: kafka.request.queue + type: updowncounter + desc: Size of the request queue + unit: '{requests}' + + - bean: kafka.server:type=BrokerTopicMetrics,name=BytesInPerSec + label: + direction: in + mapping: + Count: + metric: kafka.network.io + type: counter + desc: The bytes received or sent by the broker + unit: By + + - bean: kafka.server:type=BrokerTopicMetrics,name=BytesOutPerSec + label: + direction: out + mapping: + Count: + metric: kafka.network.io + type: counter + desc: The bytes received or sent by the broker + unit: By + + - beans: + - kafka.server:type=DelayedOperationPurgatory,name=PurgatorySize,delayedOperation=Produce + - kafka.server:type=DelayedOperationPurgatory,name=PurgatorySize,delayedOperation=Fetch + label: + type: param(delayedOperation) + mapping: + Value: + metric: kafka.purgatory.size + type: updowncounter + desc: The number of requests waiting in purgatory + unit: '{requests}' + + - bean: kafka.server:type=ReplicaManager,name=PartitionCount + mapping: + Value: + metric: kafka.partition.count + type: updowncounter + desc: The number of partitions on the broker + unit: '{partitions}' + + - bean: kafka.controller:type=KafkaController,name=OfflinePartitionsCount + mapping: + Value: + metric: kafka.partition.offline + type: updowncounter + desc: The number of partitions offline + unit: '{partitions}' + + - bean: kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions + mapping: + Value: + metric: kafka.partition.underReplicated + type: updowncounter + desc: The number of under replicated partitions + unit: '{partitions}' + + - bean: kafka.server:type=ReplicaManager,name=IsrShrinksPerSec + label: + operation: shrink + mapping: + Count: + metric: kafka.isr.operation.count + type: updowncounter + desc: The number of in-sync replica shrink and expand operations + unit: '{operations}' + + - bean: kafka.server:type=ReplicaManager,name=IsrExpandsPerSec + label: + operation: expand + mapping: + Count: + metric: kafka.isr.operation.count + type: updowncounter + desc: The number of in-sync replica shrink and expand operations + unit: '{operations}' + + - bean: kafka.server:type=ReplicaFetcherManager,name=MaxLag,clientId=Replica + mapping: + Value: + metric: kafka.lag.max + type: counter + desc: The max lag in messages between follower and leader replicas + unit: '{messages}' + + - bean: kafka.controller:type=KafkaController,name=ActiveControllerCount + mapping: + Value: + metric: kafka.controller.active.count + type: updowncounter + desc: The number of controllers active on the broker + unit: '{controllers}' + + - bean: kafka.controller:type=ControllerStats,name=LeaderElectionRateAndTimeMs + mapping: + Count: + metric: kafka.leaderElection.count + type: counter + desc: The leader election count + unit: '{elections}' + + - bean: kafka.controller:type=ControllerStats,name=UncleanLeaderElectionsPerSec + mapping: + Count: + metric: kafka.leaderElection.unclean.count + type: counter + desc: Unclean leader election count - increasing indicates broker failures + unit: '{elections}' + + # Log metrics + + - bean: kafka.log:type=LogFlushStats,name=LogFlushRateAndTimeMs + unit: ms + type: gauge + prefix: kafka.logs.flush. + mapping: + Count: + type: counter + desc: Log flush count + 50thPercentile: + metric: time.50p + desc: Log flush time - 50th percentile + 99thPercentile: + metric: time.99p + desc: Log flush time - 99th percentile diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-consumer.yaml b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-consumer.yaml new file mode 100644 index 000000000000..c5d5556657ec --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-consumer.yaml @@ -0,0 +1,80 @@ +--- +rules: + # Consumer metrics + + - bean: kafka.consumer:client-id=*,type=consumer-coordinator-metrics + label: + client-id: param(client-id) + prefix: kafka.consumer.all. + type: gauge + unit: 1 + mapping: + rebalance-latency-avg: + desc: The average time taken for a group to complete a successful rebalance + unit: ms + rebalance-latency-max: + desc: The maximum time taken for a group to complete a successful rebalance + unit: ms + rebalance-latency-total: + desc: The total time this consumer has spent in successful rebalances since creation + unit: ms + rebalance-rate-per-hour: + desc: The number of successful rebalance events per hour + rebalance-total: + desc: The total number of successful rebalance events + last-rebalance-seconds-ago: + desc: Number of seconds since the last rebalance event + unit: s + failed-rebalance-rate-per-hour: + desc: Number of failed rebalance events per hour + failed-rebalance-total: + desc: Total number of failed rebalance events + commit-latency-avg: + desc: The average time taken for a commit request + unit: ms + commit-rate: + desc: The number of commit calls per second + + - bean: kafka.consumer:client-id=*,type=consumer-fetch-manager-metrics + label: + client-id: param(client-id) + prefix: kafka.consumer.all. + type: gauge + unit: 1 + mapping: + fetch-rate: + desc: The number of fetch requests for all topics per second + fetch-size-avg: + desc: The average number of bytes fetched per request for all topics + unit: By + fetch-latency-avg: + desc: The average time taken for a fetch request + unit: ms + fetch-throttle-time-avg: + desc: The average throttle time + unit: ms + records-lag-max: + desc: Number of messages the consumer lags behind the producer + records-consumed-rate: + desc: The average number of records consumed for all topics per second + bytes-consumed-rate: + desc: The average number of bytes consumed for all topics per second + unit: By + + # Per-topic consumer metrics + + - bean: kafka.consumer:client-id=*,topic=*,type=consumer-fetch-manager-metrics + label: + client-id: param(client-id) + topic: param(topic) + prefix: kafka.consumer. + type: gauge + unit: By + mapping: + bytes-consumed-rate: + desc: The average number of bytes consumed per second + fetch-size-avg: + desc: The average number of bytes fetched per request + records-consumed-rate: + desc: The average number of records consumed per second + unit: 1 \ No newline at end of file diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-producer.yaml b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-producer.yaml new file mode 100644 index 000000000000..b7739f07a1e0 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-producer.yaml @@ -0,0 +1,63 @@ +--- +rules: + # Producer metrics + + - bean: kafka.producer:client-id=*,type=producer-metrics + label: + client-id: param(client-id) + prefix: kafka.producer.all. + type: gauge + unit: 1 + mapping: + batch-size-avg: + desc: Average number of bytes sent per partition per request + unit: By + bufferpool-wait-ratio: + desc: The fraction of time an appender waits for space allocation + compression-rate-avg: + desc: Average ratio of the compressed batch size to the uncompressed size + io-wait-time-ns-avg: + desc: The average time the I/O thread spent waiting for a socket ready for reads or writes + unit: ns + outgoing-byte-rate: + desc: The average number of outgoing bytes sent per second to all servers + unit: By + produce-throttle-time-avg: + desc: Average time a request was throttled by a broker + unit: ms + record-queue-time-avg: + desc: The average time record batches spent in the send buffer + unit: ms + record-retry-rate: + desc: The average number of retried record sends per second + request-latency-avg: + desc: The average request latency + unit: ms + request-rate: + desc: The average number of requests sent per second + unit: '{requests}' + response-rate: + desc: The average number of responses received per second + unit: '{responses}' + + # Per-topic Producer metrics + + - bean: kafka.producer:client-id=*,topic=*,type=producer-topic-metrics + label: + client-id: param(client-id) + topic: param(topic) + prefix: kafka.producer. + type: gauge + unit: 1 + mapping: + byte-rate: + desc: The average number of bytes sent per second for a topic + unit: By + compression-rate: + desc: The average compression rate of record batches for a topic + record-error-rate: + desc: The average per-second number of record sends that resulted in errors for a topic + record-retry-rate: + desc: The average per-second number of retried record sends for a topic + record-send-rate: + desc: The average number of records sent per second for a topic diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/tomcat.yaml b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/tomcat.yaml new file mode 100644 index 000000000000..309fc57163ec --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/tomcat.yaml @@ -0,0 +1,67 @@ +--- +rules: + - bean: Catalina:type=GlobalRequestProcessor,name=* + unit: 1 + prefix: http.server.tomcat. + label: + name: param(name) + mapping: + errorCount: + metric: errorCount + type: gauge + desc: The number of errors per second on all request processors + requestCount: + metric: requestCount + type: gauge + desc: The number of requests per second across all request processors + maxTime: + metric: maxTime + type: gauge + unit: ms + desc: The longest request processing time + processingTime: + metric: processingTime + type: counter + unit: ms + desc: Total time for processing all requests + bytesReceived: + metric: traffic + type: counter + unit: By + desc: The number of bytes transmitted + label: + direction: received + bytesSent: + metric: traffic + type: counter + unit: By + desc: The number of bytes transmitted + label: + direction: sent + - bean: Catalina:type=Manager,host=localhost,context=* + unit: 1 + prefix: http.server.tomcat. + type: updowncounter + label: + context: param(context) + mapping: + activeSessions: + metric: sessions.activeSessions + desc: The number of active sessions + - bean: Catalina:type=ThreadPool,name=* + unit: '{threads}' + prefix: http.server.tomcat. + type: updowncounter + label: + name: param(name) + mapping: + currentThreadCount: + metric: threads + desc: Thread Count of the Thread Pool + label: + state: idle + currentThreadsBusy: + metric: threads + desc: Thread Count of the Thread Pool + label: + state: busy \ No newline at end of file diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/wildfly.yaml b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/wildfly.yaml new file mode 100644 index 000000000000..f350e5b98466 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/wildfly.yaml @@ -0,0 +1,83 @@ +--- +rules: + - bean: jboss.as:deployment=*,subsystem=undertow + label: + deployment: param(deployment) + prefix: wildfly.session. + type: counter + unit: 1 + mapping: + sessionsCreated: + activeSessions: + type: updowncounter + expiredSessions: + rejectedSessions: + - bean: jboss.as:subsystem=undertow,server=*,http-listener=* + label: + server: param(server) + listener: param(http-listener) + prefix: wildfly.request. + type: counter + unit: 1 + mapping: + requestCount: + processingTime: + unit: ns + errorCount: + - bean: jboss.as:subsystem=undertow,server=*,http-listener=* + label: + server: param(server) + listener: param(http-listener) + type: counter + unit: By + mapping: + bytesSent: + metric: wildfly.network.io + desc: Total number of bytes transferred + label: + direction: out + bytesReceived: + metric: wildfly.network.io + desc: Total number of bytes transferred + label: + direction: in + - bean: jboss.as:subsystem=datasources,data-source=*,statistics=pool + unit: 1 + label: + data_source: param(data-source) + mapping: + ActiveCount: + metric: wildfly.db.client.connections.usage + label: + state: used + desc: The number of open jdbc connections + IdleCount: + metric: wildfly.db.client.connections.usage + label: + state: idle + desc: The number of open jdbc connections + WaitCount: + metric: wildfly.db.client.connections.WaitCount + type: counter + - bean: jboss.as:subsystem=transactions + type: counter + prefix: wildfly.db.client. + unit: "{transactions}" + mapping: + numberOfTransactions: + metric: transaction.NumberOfTransactions + numberOfApplicationRollbacks: + metric: rollback.count + label: + cause: application + desc: The total number of transactions rolled back + numberOfResourceRollbacks: + metric: rollback.count + label: + cause: resource + desc: The total number of transactions rolled back + numberOfSystemRollbacks: + metric: rollback.count + label: + cause: system + desc: The total number of transactions rolled back diff --git a/instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeExtractorTest.java b/instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeExtractorTest.java new file mode 100644 index 000000000000..272e7def86ef --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeExtractorTest.java @@ -0,0 +1,205 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Set; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectName; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class AttributeExtractorTest { + + // An MBean used for this test + // CHECKSTYLE:OFF + public interface Test1MBean { + // CHECKSTYLE:ON + byte getByteAttribute(); + + short getShortAttribute(); + + int getIntAttribute(); + + long getLongAttribute(); + + float getFloatAttribute(); + + double getDoubleAttribute(); + + String getStringAttribute(); + } + + private static class Test1 implements Test1MBean { + @Override + public byte getByteAttribute() { + return 10; + } + + @Override + public short getShortAttribute() { + return 11; + } + + @Override + public int getIntAttribute() { + return 12; + } + + @Override + public long getLongAttribute() { + return 13; + } + + @Override + public float getFloatAttribute() { + return 14.0f; + } + + @Override + public double getDoubleAttribute() { + return 15.0; + } + + @Override + public String getStringAttribute() { + return ""; + } + } + + private static final String DOMAIN = "otel.jmx.test"; + private static final String OBJECT_NAME = "otel.jmx.test:type=Test1"; + private static ObjectName objectName; + private static MBeanServer theServer; + + @BeforeAll + static void setUp() throws Exception { + theServer = MBeanServerFactory.createMBeanServer(DOMAIN); + Test1 test1 = new Test1(); + objectName = new ObjectName(OBJECT_NAME); + theServer.registerMBean(test1, objectName); + } + + @AfterAll + static void tearDown() { + MBeanServerFactory.releaseMBeanServer(theServer); + theServer = null; + } + + @Test + void testSetup() throws Exception { + Set set = theServer.queryNames(objectName, null); + assertThat(set == null).isFalse(); + assertThat(set.size() == 1).isTrue(); + assertThat(set.contains(objectName)).isTrue(); + } + + @Test + void testByteAttribute() throws Exception { + AttributeValueExtractor extractor = new AttributeValueExtractor("ByteAttribute"); + AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); + assertThat(info == null).isFalse(); + assertThat(info.usesDoubleValues()).isFalse(); + } + + @Test + void testByteAttributeValue() throws Exception { + AttributeValueExtractor extractor = new AttributeValueExtractor("ByteAttribute"); + Number number = extractor.extractNumericalAttribute(theServer, objectName); + assertThat(number == null).isFalse(); + assertThat(number.longValue() == 10).isTrue(); + } + + @Test + void testShortAttribute() throws Exception { + AttributeValueExtractor extractor = new AttributeValueExtractor("ShortAttribute"); + AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); + assertThat(info == null).isFalse(); + assertThat(info.usesDoubleValues()).isFalse(); + } + + @Test + void testShortAttributeValue() throws Exception { + AttributeValueExtractor extractor = new AttributeValueExtractor("ShortAttribute"); + Number number = extractor.extractNumericalAttribute(theServer, objectName); + assertThat(number == null).isFalse(); + assertThat(number.longValue() == 11).isTrue(); + } + + @Test + void testIntAttribute() throws Exception { + AttributeValueExtractor extractor = new AttributeValueExtractor("IntAttribute"); + AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); + assertThat(info == null).isFalse(); + assertThat(info.usesDoubleValues()).isFalse(); + } + + @Test + void testIntAttributeValue() throws Exception { + AttributeValueExtractor extractor = new AttributeValueExtractor("IntAttribute"); + Number number = extractor.extractNumericalAttribute(theServer, objectName); + assertThat(number == null).isFalse(); + assertThat(number.longValue() == 12).isTrue(); + } + + @Test + void testLongAttribute() throws Exception { + AttributeValueExtractor extractor = new AttributeValueExtractor("LongAttribute"); + AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); + assertThat(info == null).isFalse(); + assertThat(info.usesDoubleValues()).isFalse(); + } + + @Test + void testLongAttributeValue() throws Exception { + AttributeValueExtractor extractor = new AttributeValueExtractor("LongAttribute"); + Number number = extractor.extractNumericalAttribute(theServer, objectName); + assertThat(number == null).isFalse(); + assertThat(number.longValue() == 13).isTrue(); + } + + @Test + void testFloatAttribute() throws Exception { + AttributeValueExtractor extractor = new AttributeValueExtractor("FloatAttribute"); + AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); + assertThat(info == null).isFalse(); + assertThat(info.usesDoubleValues()).isTrue(); + } + + @Test + void testFloatAttributeValue() throws Exception { + AttributeValueExtractor extractor = new AttributeValueExtractor("FloatAttribute"); + Number number = extractor.extractNumericalAttribute(theServer, objectName); + assertThat(number == null).isFalse(); + assertThat(number.doubleValue() == 14.0).isTrue(); // accurate representation + } + + @Test + void testDoubleAttribute() throws Exception { + AttributeValueExtractor extractor = new AttributeValueExtractor("DoubleAttribute"); + AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); + assertThat(info == null).isFalse(); + assertThat(info.usesDoubleValues()).isTrue(); + } + + @Test + void testDoubleAttributeValue() throws Exception { + AttributeValueExtractor extractor = new AttributeValueExtractor("DoubleAttribute"); + Number number = extractor.extractNumericalAttribute(theServer, objectName); + assertThat(number == null).isFalse(); + assertThat(number.doubleValue() == 15.0).isTrue(); // accurate representation + } + + @Test + void testStringAttribute() throws Exception { + AttributeValueExtractor extractor = new AttributeValueExtractor("StringAttribute"); + AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); + assertThat(info == null).isTrue(); + } +} diff --git a/instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/RuleParserTest.java b/instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/RuleParserTest.java new file mode 100644 index 000000000000..3d145c4010f2 --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/RuleParserTest.java @@ -0,0 +1,461 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.jmx; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data.JmxConfig; +import io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data.JmxRule; +import io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data.Metric; +import io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.yaml.RuleParser; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class RuleParserTest { + private static RuleParser parser; + + @BeforeAll + static void setup() throws Exception { + parser = RuleParser.get(); + assertThat(parser == null).isFalse(); + } + + /* + * General syntax + */ + private static final String CONF2 = + "---\n" + + "rules:\n" + + " - beans:\n" + + " - OBJECT:NAME1=*\n" + + " - OBJECT:NAME2=*\n" + + " label:\n" + + " LABEL_KEY1: param(PARAMETER)\n" + + " LABEL_KEY2: attrib(ATTRIBUTE)\n" + + " prefix: METRIC_NAME_PREFIX\n" + + " mapping:\n" + + " ATTRIBUTE1:\n" + + " metric: METRIC_NAME1\n" + + " type: Gauge\n" + + " desc: DESCRIPTION1\n" + + " unit: UNIT1\n" + + " label:\n" + + " LABEL_KEY3: CONSTANT\n" + + " ATTRIBUTE2:\n" + + " metric: METRIC_NAME2\n" + + " desc: DESCRIPTION2\n" + + " unit: UNIT2\n" + + " ATTRIBUTE3:\n" + + " ATTRIBUTE4:\n" + + " - beans:\n" + + " - OBJECT:NAME3=*\n" + + " mapping:\n" + + " ATTRIBUTE3:\n" + + " metric: METRIC_NAME3\n"; + + @Test + void testConf2() throws Exception { + InputStream is = new ByteArrayInputStream(CONF2.getBytes(Charset.forName("UTF-8"))); + JmxConfig config = parser.loadConfig(is); + assertThat(config != null).isTrue(); + + List defs = config.getRules(); + assertThat(defs.size() == 2).isTrue(); + + JmxRule def1 = defs.get(0); + assertThat(def1.getBeans().size() == 2).isTrue(); + assertThat(def1.getLabel().size() == 2).isTrue(); + Map attr = def1.getMapping(); + assertThat(attr == null).isFalse(); + assertThat(attr.size() == 4).isTrue(); + + Metric m1 = attr.get("ATTRIBUTE1"); + assertThat(m1 == null).isFalse(); + assertThat("METRIC_NAME1".equals(m1.getMetric())).isTrue(); + assertThat(m1.getMetricType() == MetricBanner.Type.GAUGE).isTrue(); + assertThat("UNIT1".equals(m1.getUnit())).isTrue(); + assertThat(m1.getLabel() == null).isFalse(); + assertThat(m1.getLabel().size() == 1).isTrue(); + assertThat("CONSTANT".equals(m1.getLabel().get("LABEL_KEY3"))).isTrue(); + } + + private static final String CONF3 = + "rules:\n" + + " - bean: OBJECT:NAME3=*\n" + + " mapping:\n" + + " ATTRIBUTE31:\n" + + " ATTRIBUTE32:\n" + + " ATTRIBUTE33:\n" + + " ATTRIBUTE34:\n" + + " metric: METRIC_NAME34\n" + + " ATTRIBUTE35:\n"; + + @Test + void testConf3() throws Exception { + InputStream is = new ByteArrayInputStream(CONF3.getBytes(Charset.forName("UTF-8"))); + JmxConfig config = parser.loadConfig(is); + assertThat(config != null).isTrue(); + + List defs = config.getRules(); + assertThat(defs.size() == 1).isTrue(); + + JmxRule def1 = defs.get(0); + assertThat(def1.getBean() == null).isFalse(); + assertThat(def1.getLabel() == null).isTrue(); + Map attr = def1.getMapping(); + assertThat(attr.size() == 5).isTrue(); + + Set keys = attr.keySet(); + assertThat(keys.contains("ATTRIBUTE33")).isTrue(); + assertThat(attr.get("ATTRIBUTE33") == null).isTrue(); + assertThat(attr.get("ATTRIBUTE34") == null).isFalse(); + } + + /* + * Semantics + */ + private static final String CONF4 = + "---\n" + + "rules:\n" + + " - bean: my-test:type=4\n" + + " label:\n" + + " LABEL_KEY1: param(PARAMETER)\n" + + " LABEL_KEY2: attrib(ATTRIBUTE)\n" + + " prefix: PREFIX.\n" + + " type: upDownCounter\n" + + " unit: DEFAULT_UNIT\n" + + " mapping:\n" + + " A.b:\n" + + " metric: METRIC_NAME1\n" + + " type: counter\n" + + " desc: DESCRIPTION1\n" + + " unit: UNIT1\n" + + " label:\n" + + " LABEL_KEY3: CONSTANT\n" + + " ATTRIBUTE2:\n" + + " metric: METRIC_NAME2\n" + + " desc: DESCRIPTION2\n" + + " unit: UNIT2\n" + + " ATTRIBUTE3:\n"; + + @Test + void testConf4() throws Exception { + InputStream is = new ByteArrayInputStream(CONF4.getBytes(Charset.forName("UTF-8"))); + JmxConfig config = parser.loadConfig(is); + assertThat(config != null).isTrue(); + + List defs = config.getRules(); + assertThat(defs.size() == 1).isTrue(); + + MetricDef metricDef = defs.get(0).buildMetricDef(); + assertThat(metricDef == null).isFalse(); + assertThat(metricDef.getMetricExtractors().length == 3).isTrue(); + + MetricExtractor m1 = metricDef.getMetricExtractors()[0]; + AttributeValueExtractor a1 = m1.getMetricValueExtractor(); + assertThat("A.b".equals(a1.getAttributeName())).isTrue(); + assertThat(m1.getLabels().length == 3).isTrue(); + MetricBanner mb1 = m1.getBanner(); + assertThat("PREFIX.METRIC_NAME1".equals(mb1.getMetricName())).isTrue(); + assertThat("DESCRIPTION1".equals(mb1.getDescription())).isTrue(); + assertThat("UNIT1".equals(mb1.getUnit())).isTrue(); + assertThat(MetricBanner.Type.COUNTER == mb1.getType()).isTrue(); + + MetricExtractor m3 = metricDef.getMetricExtractors()[2]; + AttributeValueExtractor a3 = m3.getMetricValueExtractor(); + assertThat("ATTRIBUTE3".equals(a3.getAttributeName())).isTrue(); + MetricBanner mb3 = m3.getBanner(); + assertThat("PREFIX.ATTRIBUTE3".equals(mb3.getMetricName())).isTrue(); + // syntax extension - defining a default unit and type + assertThat(MetricBanner.Type.UPDOWNCOUNTER == mb3.getType()).isTrue(); + assertThat("DEFAULT_UNIT".equals(mb3.getUnit())).isTrue(); + } + + private static final String CONF5 = // minimal valid definition + "--- # keep stupid spotlessJava at bay\n" + + "rules:\n" + + " - bean: my-test:type=5\n" + + " mapping:\n" + + " ATTRIBUTE:\n"; + + @Test + void testConf5() throws Exception { + InputStream is = new ByteArrayInputStream(CONF5.getBytes(Charset.forName("UTF-8"))); + JmxConfig config = parser.loadConfig(is); + assertThat(config != null).isTrue(); + + List defs = config.getRules(); + assertThat(defs.size() == 1).isTrue(); + + MetricDef metricDef = defs.get(0).buildMetricDef(); + assertThat(metricDef == null).isFalse(); + assertThat(metricDef.getMetricExtractors().length == 1).isTrue(); + + MetricExtractor m1 = metricDef.getMetricExtractors()[0]; + AttributeValueExtractor a1 = m1.getMetricValueExtractor(); + assertThat("ATTRIBUTE".equals(a1.getAttributeName())).isTrue(); + assertThat(m1.getLabels().length == 0).isTrue(); + MetricBanner mb1 = m1.getBanner(); + assertThat("ATTRIBUTE".equals(mb1.getMetricName())).isTrue(); + assertThat(MetricBanner.Type.GAUGE == mb1.getType()).isTrue(); + assertThat(null == mb1.getUnit()).isTrue(); + } + + private static final String CONF6 = // merging label sets with same keys + "--- # keep stupid spotlessJava at bay\n" + + "rules:\n" + + " - bean: my-test:type=6\n" + + " label:\n" + + " key1: value1\n" + + " mapping:\n" + + " ATTRIBUTE:\n" + + " label:\n" + + " key1: value2\n"; + + @Test + void testConf6() throws Exception { + InputStream is = new ByteArrayInputStream(CONF6.getBytes(Charset.forName("UTF-8"))); + JmxConfig config = parser.loadConfig(is); + assertThat(config != null).isTrue(); + + List defs = config.getRules(); + assertThat(defs.size() == 1).isTrue(); + + MetricDef metricDef = defs.get(0).buildMetricDef(); + assertThat(metricDef == null).isFalse(); + assertThat(metricDef.getMetricExtractors().length == 1).isTrue(); + + MetricExtractor m1 = metricDef.getMetricExtractors()[0]; + AttributeValueExtractor a1 = m1.getMetricValueExtractor(); + assertThat("ATTRIBUTE".equals(a1.getAttributeName())).isTrue(); + // MetricLabel set at the metric level should override the one set at the definition level + assertThat(m1.getLabels().length == 1).isTrue(); + MetricLabel l1 = m1.getLabels()[0]; + assertThat("value2".equals(l1.extractLabelValue(null, null))).isTrue(); + MetricBanner mb1 = m1.getBanner(); + assertThat("ATTRIBUTE".equals(mb1.getMetricName())).isTrue(); + } + + private static final String CONF7 = // merging label sets with different keys + "--- # keep stupid spotlessJava at bay\n" + + "rules:\n" + + " - bean: my-test:type=7\n" + + " label:\n" + + " key1: value1\n" + + " mapping:\n" + + " ATTRIBUTE:\n" + + " label:\n" + + " key2: value2\n"; + + @Test + void testConf7() throws Exception { + InputStream is = new ByteArrayInputStream(CONF7.getBytes(Charset.forName("UTF-8"))); + JmxConfig config = parser.loadConfig(is); + assertThat(config != null).isTrue(); + + List defs = config.getRules(); + assertThat(defs.size() == 1).isTrue(); + + MetricDef metricDef = defs.get(0).buildMetricDef(); + assertThat(metricDef == null).isFalse(); + assertThat(metricDef.getMetricExtractors().length == 1).isTrue(); + + MetricExtractor m1 = metricDef.getMetricExtractors()[0]; + AttributeValueExtractor a1 = m1.getMetricValueExtractor(); + assertThat("ATTRIBUTE".equals(a1.getAttributeName())).isTrue(); + assertThat(m1.getLabels().length == 2).isTrue(); + MetricBanner mb1 = m1.getBanner(); + assertThat("ATTRIBUTE".equals(mb1.getMetricName())).isTrue(); + } + + private static final String EMPTY_CONF = "---\n"; + + @Test + void testEmptyConf() throws Exception { + InputStream is = new ByteArrayInputStream(EMPTY_CONF.getBytes(Charset.forName("UTF-8"))); + JmxConfig config = parser.loadConfig(is); + assertThat(config == null).isTrue(); + } + + /* + * Negative tests + */ + + private static void runNegativeTest(String yaml) throws Exception { + InputStream is = new ByteArrayInputStream(yaml.getBytes(Charset.forName("UTF-8"))); + + Assertions.assertThrows( + Exception.class, + () -> { + JmxConfig config = parser.loadConfig(is); + assertThat(config != null).isTrue(); + + List defs = config.getRules(); + assertThat(defs.size() == 1).isTrue(); + defs.get(0).buildMetricDef(); + }); + } + + @Test + void testNoBeans() throws Exception { + String yaml = + "--- # keep stupid spotlessJava at bay\n" + + "rules: # no bean\n" + + " - mapping: # still no beans\n" + + " A:\n" + + " metric: METRIC_NAME\n"; + runNegativeTest(yaml); + } + + @Test + void testInvalidObjectName() throws Exception { + String yaml = + "--- # keep stupid spotlessJava at bay\n" + + "rules:\n" + + " - bean: BAD_OBJECT_NAME\n" + + " mapping:\n" + + " A:\n" + + " metric: METRIC_NAME\n"; + runNegativeTest(yaml); + } + + @Test + void testEmptyMapping() throws Exception { + String yaml = + "--- # keep stupid spotlessJava at bay\n " + + "rules:\n" + + " - bean: domain:type=6\n" + + " mapping:\n"; + runNegativeTest(yaml); + } + + @Test + void testInvalidAttributeName() throws Exception { + String yaml = + "--- # keep stupid spotlessJava at bay\n" + + "rules:\n" + + " - bean: domain:name=you\n" + + " mapping:\n" + + " .used:\n" + + " metric: METRIC_NAME\n"; + runNegativeTest(yaml); + } + + @Test + void testInvalidTag() throws Exception { + String yaml = + "--- # keep stupid spotlessJava at bay\n" + + "rules:\n" + + " - bean: domain:name=you\n" + + " mapping:\n" + + " ATTRIB:\n" + + " label:\n" + + " LABEL: attr(something)\n" + + " metric: METRIC_NAME\n"; + runNegativeTest(yaml); + } + + @Test + void testInvalidType() throws Exception { + String yaml = + "--- # keep stupid spotlessJava at bay\n" + + "rules:\n" + + " - bean: domain:name=you\n" + + " mapping:\n" + + " ATTRIB:\n" + + " type: gage\n" + + " metric: METRIC_NAME\n"; + runNegativeTest(yaml); + } + + @Test + void testInvalidTagFromAttribute() throws Exception { + String yaml = + "--- # keep stupid spotlessJava at bay\n" + + "rules:\n" + + " - bean: domain:name=you\n" + + " mapping:\n" + + " ATTRIB:\n" + + " label:\n" + + " LABEL: attrib(.used)\n" + + " metric: METRIC_NAME\n"; + runNegativeTest(yaml); + } + + @Test + void testEmptyTagFromAttribute() throws Exception { + String yaml = + "--- # keep stupid spotlessJava at bay\n" + + "rules:\n" + + " - bean: domain:name=you\n" + + " mapping:\n" + + " ATTRIB:\n" + + " label:\n" + + " LABEL: attrib( )\n" + + " metric: METRIC_NAME\n"; + runNegativeTest(yaml); + } + + @Test + void testEmptyTagFromParameter() throws Exception { + String yaml = + "--- # keep stupid spotlessJava at bay\n" + + "rules:\n" + + " - bean: domain:name=you\n" + + " mapping:\n" + + " ATTRIB:\n" + + " label:\n" + + " LABEL: param( )\n" + + " metric: METRIC_NAME\n"; + runNegativeTest(yaml); + } + + @Test + void testEmptyPrefix() throws Exception { + String yaml = + "---\n" + + "rules:\n" + + " - bean: domain:name=you\n" + + " prefix:\n" + + " mapping:\n" + + " A:\n" + + " metric: METRIC_NAME\n"; + runNegativeTest(yaml); + } + + @Test + void testTypoInMetric() throws Exception { + String yaml = + "---\n" + + "rules:\n" + + " - bean: domain:name=you\n" + + " mapping:\n" + + " A:\n" + + " metrics: METRIC_NAME\n"; + runNegativeTest(yaml); + } + + @Test + void testMessedUpSyntax() throws Exception { + String yaml = + "---\n" + + "rules:\n" + + " - bean: domain:name=you\n" + + " mapping:\n" + + " label: # not valid here\n" + + " key: value\n" + + " A:\n" + + " metric: METRIC_NAME\n"; + runNegativeTest(yaml); + } +} diff --git a/instrumentation/runtime-metrics/library/tomcat.md b/instrumentation/runtime-metrics/library/tomcat.md new file mode 100644 index 000000000000..a2ea859d8077 --- /dev/null +++ b/instrumentation/runtime-metrics/library/tomcat.md @@ -0,0 +1,13 @@ +# Tomcat Metrics + +Here is the list of metrics based on MBeans exposed by Tomcat. + +| Metric Name | Type | Attributes | Description | +|--------------------------------------------|---------------|-----------------|-----------------------------------------------------------------| +| http.server.tomcat.sessions.activeSessions | UpDownCounter | context | The number of active sessions | +| http.server.tomcat.errorCount | Gauge | name | The number of errors per second on all request processors | +| http.server.tomcat.requestCount | Gauge | name | The number of requests per second across all request processors | +| http.server.tomcat.maxTime | Gauge | name | The longest request processing time | +| http.server.tomcat.processingTime | Counter | name | Represents the total time for processing all requests | +| http.server.tomcat.traffic | Counter | name, direction | The number of bytes transmitted | +| http.server.tomcat.threads | UpDownCounter | name, state | Thread Count of the Thread Pool | diff --git a/instrumentation/runtime-metrics/library/wildfly.md b/instrumentation/runtime-metrics/library/wildfly.md new file mode 100644 index 000000000000..c88eee63be0f --- /dev/null +++ b/instrumentation/runtime-metrics/library/wildfly.md @@ -0,0 +1,18 @@ +# Wildfly Metrics + +Here is the list of metrics based on MBeans exposed by Wildfly. + +| Metric Name | Type | Attributes | Description | +|----------------------------------------------------|---------------|--------------------|-------------------------------------------------------------------------| +| wildfly.network.io | Counter | direction, server | Total number of bytes transferred | +| wildfly.request.errorCount | Counter | server, listener | The number of 500 responses that have been sent by this listener | +| wildfly.request.requestCount | Counter | server, listener | The number of requests this listener has served | +| wildfly.request.processingTime | Counter | server, listener | The total processing time of all requests handed by this listener | +| wildfly.session.expiredSession | Counter | deployment | Number of sessions that have expired | +| wildfly.session.rejectedSessions | Counter | deployment | Number of rejected sessions | +| wildfly.session.sessionsCreated | Counter | deployment | Total sessions created | +| wildfly.session.activeSessions | UpDownCounter | deployment | Number of active sessions | +| wildfly.db.client.connections.usage | Gauge | data_source, state | The number of open jdbc connections | +| wildfly.db.client.connections.WaitCount | Counter | data_source | The number of requests that had to wait to obtain a physical connection | +| wildfly.db.client.rollback.count | Counter | cause | The total number of transactions rolled back | +| wildfly.db.client.transaction.NumberOfTransactions | Counter | | The total number of transactions (top-level and nested) created | From 58f9e1912bcbc0f1fcccde584f08bb84760f74ef Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Fri, 9 Sep 2022 16:29:22 -0700 Subject: [PATCH 02/20] JMX Metric Insight Correcting a typo in a comment. --- .../instrumentation/runtimemetrics/jmx/AttributeInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeInfo.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeInfo.java index 71a2020dc58a..39990a75ee56 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeInfo.java +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeInfo.java @@ -6,7 +6,7 @@ package io.opentelemetry.instrumentation.runtimemetrics.jmx; /** - * A class holding relevant information about an MBean atribute which will be used for collecting + * A class holding relevant information about an MBean attribute which will be used for collecting * metric values. The info comes directly from the relevant MBeans. */ class AttributeInfo { From 5f29c94f9f9484a5b52fb9e36824acc25646801a Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Thu, 22 Sep 2022 17:09:32 -0700 Subject: [PATCH 03/20] JMX Metric Insight Using the latest version of snakeyaml. Version 1.30 had this vulnerability https://nvd.nist.gov/vuln/detail/CVE-2022-25857. --- instrumentation/runtime-metrics/library/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/runtime-metrics/library/build.gradle.kts b/instrumentation/runtime-metrics/library/build.gradle.kts index 44514a4931da..24a033152053 100644 --- a/instrumentation/runtime-metrics/library/build.gradle.kts +++ b/instrumentation/runtime-metrics/library/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } dependencies { - implementation("org.yaml:snakeyaml:1.30") + implementation("org.yaml:snakeyaml") compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") From 9dfe6aa0e44419273de960b43607026f990dfd65 Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Mon, 26 Sep 2022 11:48:12 -0700 Subject: [PATCH 04/20] Updating the documentation to clarify that examples are just for illustrative purposes. --- .../runtime-metrics/library/README.md | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/instrumentation/runtime-metrics/library/README.md b/instrumentation/runtime-metrics/library/README.md index 781f08adcd77..4473e687ba9d 100644 --- a/instrumentation/runtime-metrics/library/README.md +++ b/instrumentation/runtime-metrics/library/README.md @@ -50,12 +50,12 @@ rules: - bean: java.lang:type=Threading mapping: ThreadCount: - metric: jvm.thread.count + metric: my.own.jvm.thread.count type: updowncounter desc: The current number of threads unit: 1 ``` -MBeans are identified by unique [ObjectNames](https://docs.oracle.com/javase/8/docs/api/javax/management/ObjectName.html). In the example above, the object name `java.lang:type=Threading` identifies one of the standard JVM MBeans, which can be used to access a number of internal JVM statistics related to threads. For that MBean, we specify its attribute `ThreadCount` which reflects the number of currently active (alive) threads. The values of this attribute will be reported by a metric named `jvm.thread.count`. The declared OpenTelemetry type of the metric is declared as `updowncounter` which indicates that the value is a sum which can go up or down over time. Metric description and/or unit can also be specified. +MBeans are identified by unique [ObjectNames](https://docs.oracle.com/javase/8/docs/api/javax/management/ObjectName.html). In the example above, the object name `java.lang:type=Threading` identifies one of the standard JVM MBeans, which can be used to access a number of internal JVM statistics related to threads. For that MBean, we specify its attribute `ThreadCount` which reflects the number of currently active (alive) threads. The values of this attribute will be reported by a metric named `my.own.jvm.thread.count`. The declared OpenTelemetry type of the metric is declared as `updowncounter` which indicates that the value is a sum which can go up or down over time. Metric description and/or unit can also be specified. All metrics reported by the service are backed by [asynchronous instruments](https://opentelemetry.io/docs/reference/specification/metrics/api/#synchronous-and-asynchronous-instruments) which can be a @@ -74,17 +74,17 @@ rules: - bean: java.lang:type=Memory mapping: HeapMemoryUsage.used: - metric: jvm.heap.used + metric: my.own.jvm.heap.used type: updowncounter desc: The current heap size - unit: B + unit: By HeapMemoryUsage.max: - metric: jvm.heap.max + metric: my.own.jvm.heap.max type: updowncounter desc: The maximum allowed heap size - unit: B + unit: By ``` -The MBean responsible for memory statistics, identified by ObjectName `java.lang:type=Memory` has an attribute named `HeapMemoryUsage`, which is of a `CompositeType`. This type represents a collection of fields with values (very much like the traditional `struct` data type). To access individual fields of the structure we use a dot which separates the MBean attribute name from the field name. The values are reported in bytes, which here we indicate by `B`. In the above example, the current heap size and the maximum allowed heap size will be reported as two metrics, named `jvm.heap.used`, and `jvm.heap.max`. +The MBean responsible for memory statistics, identified by ObjectName `java.lang:type=Memory` has an attribute named `HeapMemoryUsage`, which is of a `CompositeType`. This type represents a collection of fields with values (very much like the traditional `struct` data type). To access individual fields of the structure we use a dot which separates the MBean attribute name from the field name. The values are reported in bytes, which here we indicate by `By`. In the above example, the current heap size and the maximum allowed heap size will be reported as two metrics, named `my.own.jvm.heap.used`, and `my.own.jvm.heap.max`. ### Measurement Attributes @@ -99,15 +99,15 @@ rules: type: attrib(Type) mapping: Usage.used: - metric: jvm.memory.pool.used + metric: my.own.jvm.memory.pool.used type: updowncounter desc: Pool memory currently used - unit: B + unit: By Usage.max: - metric: jvm.memory.pool.max + metric: my.own.jvm.memory.pool.max type: updowncounter desc: Maximum obtainable memory pool size - unit: B + unit: By ``` The ObjectName pattern will match a number of MBeans, each for a different memory pool. The number and names of available memory pools, however, will be known only at runtime. To report values for all actual memory pools using only two metrics, we use metric attributes (referenced by the configuration file as `label`s). The first metric attribute, named `pool` will have its value derived from the ObjectName parameter `name` - which corresponds to the memory pool name. The second metric attribute, named `type` will get its value from the corresponding MBean attribute named `Type`. The values of this attribute are strings `HEAP` or `NON_HEAP` classifying the corresponding memory pool. Here the definition of the metric attributes is shared by both metrics, but it is also possible to define them at the individual metric level. @@ -122,6 +122,8 @@ Using the above rule, when running on HotSpot JVM for Java 11, the following com - {pool="CodeHeap 'non-nmethods'", type="NON_HEAP"} - {pool="G1 Survivor Space", type="HEAP"} +**Note**: Heap and memory pool metrics above are given just as examples. The Java Agent already reports such metrics, no additional configuration is needed from the users. + ### Mapping multiple MBean attributes to the same metric Sometimes it is desired to merge several MBean attributes into a single metric, as shown in the next example. @@ -139,13 +141,13 @@ rules: label: direction: in desc: The number of transmitted bytes - unit: B + unit: By bytesSent: metric: catalina.traffic label: direction: out desc: The number of transmitted bytes - unit: B + unit: By ``` The referenced MBean has two attributes of interest, `bytesReceived`, and `bytesSent`. We want them to be reported by just one metric, but keeping the values separate by using metric attribute `direction`. This is achieved by specifying the same metric name `catalina.traffic` when mapping the MBean attributes to metrics. There will be two metric attributes provided: `handler`, which has a shared definition, and `direction`, which has its value (`in` or `out`) declared directly, depending on the MBean attribute providing the metric value. @@ -164,7 +166,7 @@ rules: - bean: kafka.streams:type=stream-thread-metrics,thread-id=* label: threadId: param(thread-id) - prefix: kafka.streams. + prefix: my.kafka.streams. unit: ms mapping: commit-latency-avg: @@ -182,7 +184,7 @@ rules: - bean: kafka.streams:type=stream-thread-metrics,thread-id=* label: threadId: param(thread-id) - prefix: kafka.streams. + prefix: my.kafka.streams. unit: /s type: gauge mapping: @@ -194,7 +196,7 @@ rules: - bean: kafka.streams:type=stream-thread-metrics,thread-id=* label: threadId: param(thread-id) - prefix: kafka.streams.totals. + prefix: my.kafka.streams.totals. unit: 1 type: counter mapping: @@ -204,8 +206,8 @@ rules: task-created-total: task-closed-total: ``` -Because we declared metric prefix (here `kafka.streams.`) and did not specify actual metric names, the metric names will be generated automatically, by appending the corresponding MBean attribute name to the prefix. -Thus, the above definitions will create several metrics, named `kafka.streams.commit-latency-avg`, `kafka.streams.commit-latency-max`, and so on. For the first configuration rule, the default unit has been changed to `ms`, which remains in effect for all attribute mappings listed within the rule, unless they define their own unit. Similarly, the second configuration rule defines the unit as `/s`, valid for all the rates reported. +Because we declared metric prefix (here `my.kafka.streams.`) and did not specify actual metric names, the metric names will be generated automatically, by appending the corresponding MBean attribute name to the prefix. +Thus, the above definitions will create several metrics, named `my.kafka.streams.commit-latency-avg`, `my.kafka.streams.commit-latency-max`, and so on. For the first configuration rule, the default unit has been changed to `ms`, which remains in effect for all attribute mappings listed within the rule, unless they define their own unit. Similarly, the second configuration rule defines the unit as `/s`, valid for all the rates reported. The metric descriptions will remain undefined, unless they are provided by the queried MBeans. From 7cebb636ae0ec12894e61a81cd9915afee371c6a Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Wed, 28 Sep 2022 10:03:21 -0700 Subject: [PATCH 05/20] Code refactoring and changes, moving to own module :instrumentation:jmx. --- .../library => jmx/javaagent}/README.md | 0 .../library => jmx/javaagent}/activemq.md | 0 .../jmx/javaagent/build.gradle.kts | 10 ++ .../library => jmx/javaagent}/hadoop.md | 0 .../library => jmx/javaagent}/jetty.md | 4 +- .../library => jmx/javaagent}/kafka-broker.md | 2 +- .../javaagent}/kafka-consumer.md | 0 .../javaagent}/kafka-producer.md | 0 .../jmx/JmxMetricInsightInstaller.java | 89 +++++++++++++++ .../main/resources/jmx/rules/activemq.yaml | 0 .../src/main/resources/jmx/rules/hadoop.yaml | 0 .../src/main/resources/jmx/rules/jetty.yaml | 4 +- .../resources/jmx/rules/kafka-broker.yaml | 1 - .../resources/jmx/rules/kafka-consumer.yaml | 0 .../resources/jmx/rules/kafka-producer.yaml | 0 .../src/main/resources/jmx/rules/tomcat.yaml | 0 .../src/main/resources/jmx/rules/wildfly.yaml | 0 .../library => jmx/javaagent}/tomcat.md | 0 .../library => jmx/javaagent}/wildfly.md | 0 .../jmx/jmx-engine/library/build.gradle.kts | 10 ++ .../jmx/engine}/AttributeInfo.java | 2 +- .../jmx/engine}/AttributeValueExtractor.java | 22 ++-- .../jmx/engine}/BeanFinder.java | 2 +- .../instrumentation/jmx/engine}/BeanPack.java | 4 +- .../jmx/engine}/DetectionStatus.java | 4 +- .../jmx/engine/JmxMetricInsight.java | 49 +++++++++ .../jmx/engine}/LabelExtractor.java | 2 +- .../jmx/engine}/MetricBanner.java | 4 +- .../jmx/engine}/MetricConfiguration.java | 2 +- .../jmx/engine}/MetricDef.java | 4 +- .../jmx/engine}/MetricExtractor.java | 2 +- .../jmx/engine}/MetricLabel.java | 4 +- .../jmx/engine}/MetricRegistrar.java | 11 +- .../jmx/engine}/AttributeExtractorTest.java | 2 +- .../jmx/jmx-yaml/library/build.gradle.kts | 10 ++ .../instrumentation/jmx/yaml}/JmxConfig.java | 6 +- .../instrumentation/jmx/yaml}/JmxRule.java | 18 ++-- .../instrumentation/jmx/yaml}/Metric.java | 4 +- .../jmx/yaml}/MetricStructure.java | 6 +- .../instrumentation/jmx}/yaml/RuleParser.java | 15 ++- .../jmx/engine}/RuleParserTest.java | 13 ++- .../RuntimeMetricsInstaller.java | 29 +++-- .../runtimemetrics/jmx/MetricService.java | 101 ------------------ settings.gradle.kts | 3 + 44 files changed, 255 insertions(+), 184 deletions(-) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/README.md (100%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/activemq.md (100%) create mode 100644 instrumentation/jmx/javaagent/build.gradle.kts rename instrumentation/{runtime-metrics/library => jmx/javaagent}/hadoop.md (100%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/jetty.md (91%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/kafka-broker.md (98%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/kafka-consumer.md (100%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/kafka-producer.md (100%) create mode 100644 instrumentation/jmx/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java rename instrumentation/{runtime-metrics/library => jmx/javaagent}/src/main/resources/jmx/rules/activemq.yaml (100%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/src/main/resources/jmx/rules/hadoop.yaml (100%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/src/main/resources/jmx/rules/jetty.yaml (93%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/src/main/resources/jmx/rules/kafka-broker.yaml (99%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/src/main/resources/jmx/rules/kafka-consumer.yaml (100%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/src/main/resources/jmx/rules/kafka-producer.yaml (100%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/src/main/resources/jmx/rules/tomcat.yaml (100%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/src/main/resources/jmx/rules/wildfly.yaml (100%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/tomcat.md (100%) rename instrumentation/{runtime-metrics/library => jmx/javaagent}/wildfly.md (100%) create mode 100644 instrumentation/jmx/jmx-engine/library/build.gradle.kts rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine}/AttributeInfo.java (95%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine}/AttributeValueExtractor.java (93%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine}/BeanFinder.java (98%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine}/BeanPack.java (91%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine}/DetectionStatus.java (88%) create mode 100644 instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine}/LabelExtractor.java (86%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine}/MetricBanner.java (92%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine}/MetricConfiguration.java (90%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine}/MetricDef.java (92%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine}/MetricExtractor.java (95%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine}/MetricLabel.java (92%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine}/MetricRegistrar.java (94%) rename instrumentation/{runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-engine/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine}/AttributeExtractorTest.java (99%) create mode 100644 instrumentation/jmx/jmx-yaml/library/build.gradle.kts rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data => jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml}/JmxConfig.java (83%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data => jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml}/JmxRule.java (91%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data => jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml}/Metric.java (91%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data => jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml}/MetricStructure.java (94%) rename instrumentation/{runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf => jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx}/yaml/RuleParser.java (85%) rename instrumentation/{runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx => jmx/jmx-yaml/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine}/RuleParserTest.java (97%) delete mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricService.java diff --git a/instrumentation/runtime-metrics/library/README.md b/instrumentation/jmx/javaagent/README.md similarity index 100% rename from instrumentation/runtime-metrics/library/README.md rename to instrumentation/jmx/javaagent/README.md diff --git a/instrumentation/runtime-metrics/library/activemq.md b/instrumentation/jmx/javaagent/activemq.md similarity index 100% rename from instrumentation/runtime-metrics/library/activemq.md rename to instrumentation/jmx/javaagent/activemq.md diff --git a/instrumentation/jmx/javaagent/build.gradle.kts b/instrumentation/jmx/javaagent/build.gradle.kts new file mode 100644 index 000000000000..0804b9a57cfe --- /dev/null +++ b/instrumentation/jmx/javaagent/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +dependencies { + implementation(project(":instrumentation:jmx:jmx-engine:library")) + implementation(project(":instrumentation:jmx:jmx-yaml:library")) + + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") +} diff --git a/instrumentation/runtime-metrics/library/hadoop.md b/instrumentation/jmx/javaagent/hadoop.md similarity index 100% rename from instrumentation/runtime-metrics/library/hadoop.md rename to instrumentation/jmx/javaagent/hadoop.md diff --git a/instrumentation/runtime-metrics/library/jetty.md b/instrumentation/jmx/javaagent/jetty.md similarity index 91% rename from instrumentation/runtime-metrics/library/jetty.md rename to instrumentation/jmx/javaagent/jetty.md index 646edaea29aa..e04622a17918 100644 --- a/instrumentation/runtime-metrics/library/jetty.md +++ b/instrumentation/jmx/javaagent/jetty.md @@ -5,8 +5,8 @@ Here is the list of metrics based on MBeans exposed by Jetty. | Metric Name | Type | Attributes | Description | |--------------------------------|---------------|--------------|------------------------------------------------------| | jetty.session.sessionsCreated | Counter | resource | The number of sessions established in total | -| jetty.session.sessionTimeTotal | UpDownCounter | resource | The total time sessions have been active | -| jetty.session.sessionTimeMax | UpDownCounter | resource | The maximum amount of time a session has been active | +| jetty.session.sessionTimeTotal | Counter | resource | The total time sessions have been active | +| jetty.session.sessionTimeMax | Gauge | resource | The maximum amount of time a session has been active | | jetty.session.sessionTimeMean | Gauge | resource | The mean time sessions remain active | | jetty.threads.busyThreads | UpDownCounter | | The current number of busy threads | | jetty.threads.idleThreads | UpDownCounter | | The current number of idle threads | diff --git a/instrumentation/runtime-metrics/library/kafka-broker.md b/instrumentation/jmx/javaagent/kafka-broker.md similarity index 98% rename from instrumentation/runtime-metrics/library/kafka-broker.md rename to instrumentation/jmx/javaagent/kafka-broker.md index beac186a4f1e..2dddfbb19d82 100644 --- a/instrumentation/runtime-metrics/library/kafka-broker.md +++ b/instrumentation/jmx/javaagent/kafka-broker.md @@ -18,7 +18,7 @@ Broker metrics: | kafka.partition.offline | UpDownCounter | | The number of partitions offline | | kafka.partition.underReplicated | UpDownCounter | | The number of under replicated partitions | | kafka.isr.operation.count | UpDownCounter | operation | The number of in-sync replica shrink and expand operations | -| kafka.lag.max | Counter | | The max lag in messages between follower and leader replicas | +| kafka.lag.max | Gauge | | The max lag in messages between follower and leader replicas | | kafka.controller.active.count | UpDownCounter | | The number of controllers active on the broker | | kafka.leaderElection.count | Counter | | The leader election count | | kafka.leaderElection.unclean.count | Counter | | Unclean leader election count - increasing indicates broker failures | diff --git a/instrumentation/runtime-metrics/library/kafka-consumer.md b/instrumentation/jmx/javaagent/kafka-consumer.md similarity index 100% rename from instrumentation/runtime-metrics/library/kafka-consumer.md rename to instrumentation/jmx/javaagent/kafka-consumer.md diff --git a/instrumentation/runtime-metrics/library/kafka-producer.md b/instrumentation/jmx/javaagent/kafka-producer.md similarity index 100% rename from instrumentation/runtime-metrics/library/kafka-producer.md rename to instrumentation/jmx/javaagent/kafka-producer.md diff --git a/instrumentation/jmx/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java b/instrumentation/jmx/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java new file mode 100644 index 000000000000..6b365c6bffb4 --- /dev/null +++ b/instrumentation/jmx/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java @@ -0,0 +1,89 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.javaagent.jmx; + +import static java.util.logging.Level.CONFIG; +import static java.util.logging.Level.FINE; + +import com.google.auto.service.AutoService; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.instrumentation.jmx.engine.JmxMetricInsight; +import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration; +import io.opentelemetry.instrumentation.jmx.yaml.RuleParser; +import io.opentelemetry.javaagent.extension.AgentListener; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import java.io.File; +import java.io.InputStream; +import java.nio.file.Files; + +/** An {@link AgentListener} that enables JMX metrics during agent startup. */ +@AutoService(AgentListener.class) +public class JmxMetricInsightInstaller implements AgentListener { + + @Override + public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { + ConfigProperties config = autoConfiguredSdk.getConfig(); + + if (config.getBoolean("otel.jmx.enabled", true)) { + JmxMetricInsight service = JmxMetricInsight.createService(GlobalOpenTelemetry.get(), config); + MetricConfiguration conf = buildMetricConfiguration(); + service.start(conf); + } + } + + private static String resourceFor(String platform) { + return "/jmx/rules/" + platform + ".yaml"; + } + + private static void addRulesForPlatform(String platform, MetricConfiguration conf) { + String yamlResource = resourceFor(platform); + try (InputStream inputStream = + JmxMetricInsightInstaller.class.getResourceAsStream(yamlResource)) { + if (inputStream != null) { + JmxMetricInsight.getLogger().log(FINE, "Opened input stream {0}", yamlResource); + RuleParser parserInstance = RuleParser.get(); + parserInstance.addMetricDefs(conf, inputStream); + } else { + JmxMetricInsight.getLogger().log(CONFIG, "No support found for {0}", platform); + } + } catch (Exception e) { + JmxMetricInsight.getLogger().warning(e.getMessage()); + } + } + + private static void buildFromDefaultRules(MetricConfiguration conf) { + String targetSystem = System.getProperty("otel.jmx.target.system", "").trim(); + String[] platforms = targetSystem.length() == 0 ? new String[0] : targetSystem.split(","); + + for (String platform : platforms) { + addRulesForPlatform(platform, conf); + } + } + + private static void buildFromUserRules(MetricConfiguration conf) { + String jmxDir = System.getProperty("otel.jmx.config"); + if (jmxDir != null) { + JmxMetricInsight.getLogger().log(CONFIG, "JMX config file name: {0}", jmxDir); + RuleParser parserInstance = RuleParser.get(); + try (InputStream inputStream = Files.newInputStream(new File(jmxDir.trim()).toPath())) { + parserInstance.addMetricDefs(conf, inputStream); + } catch (Exception e) { + JmxMetricInsight.getLogger().warning(e.getMessage()); + } + } + } + + private static MetricConfiguration buildMetricConfiguration() { + MetricConfiguration conf = new MetricConfiguration(); + + buildFromDefaultRules(conf); + + buildFromUserRules(conf); + + return conf; + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/activemq.yaml b/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/activemq.yaml similarity index 100% rename from instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/activemq.yaml rename to instrumentation/jmx/javaagent/src/main/resources/jmx/rules/activemq.yaml diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/hadoop.yaml b/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/hadoop.yaml similarity index 100% rename from instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/hadoop.yaml rename to instrumentation/jmx/javaagent/src/main/resources/jmx/rules/hadoop.yaml diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/jetty.yaml similarity index 93% rename from instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/jetty.yaml rename to instrumentation/jmx/javaagent/src/main/resources/jmx/rules/jetty.yaml index d387a2d16a8e..610c37ea3f48 100644 --- a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/jetty.yaml +++ b/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/jetty.yaml @@ -13,8 +13,10 @@ rules: type: counter desc: The number of sessions established in total sessionTimeTotal: + type: counter desc: The total time sessions have been active sessionTimeMax: + type: gauge desc: The maximum amount of time a session has been active sessionTimeMean: type: gauge @@ -51,4 +53,4 @@ rules: LoggerCount: type: updowncounter unit: 1 - desc: The number of registered loggers by name \ No newline at end of file + desc: The number of registered loggers by name diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-broker.yaml b/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-broker.yaml similarity index 99% rename from instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-broker.yaml rename to instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-broker.yaml index 584c90d2db29..f85c58a999e1 100644 --- a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-broker.yaml +++ b/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-broker.yaml @@ -159,7 +159,6 @@ rules: mapping: Value: metric: kafka.lag.max - type: counter desc: The max lag in messages between follower and leader replicas unit: '{messages}' diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-consumer.yaml b/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-consumer.yaml similarity index 100% rename from instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-consumer.yaml rename to instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-consumer.yaml diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-producer.yaml b/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-producer.yaml similarity index 100% rename from instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/kafka-producer.yaml rename to instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-producer.yaml diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/tomcat.yaml b/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/tomcat.yaml similarity index 100% rename from instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/tomcat.yaml rename to instrumentation/jmx/javaagent/src/main/resources/jmx/rules/tomcat.yaml diff --git a/instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/wildfly.yaml b/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/wildfly.yaml similarity index 100% rename from instrumentation/runtime-metrics/library/src/main/resources/jmx/rules/wildfly.yaml rename to instrumentation/jmx/javaagent/src/main/resources/jmx/rules/wildfly.yaml diff --git a/instrumentation/runtime-metrics/library/tomcat.md b/instrumentation/jmx/javaagent/tomcat.md similarity index 100% rename from instrumentation/runtime-metrics/library/tomcat.md rename to instrumentation/jmx/javaagent/tomcat.md diff --git a/instrumentation/runtime-metrics/library/wildfly.md b/instrumentation/jmx/javaagent/wildfly.md similarity index 100% rename from instrumentation/runtime-metrics/library/wildfly.md rename to instrumentation/jmx/javaagent/wildfly.md diff --git a/instrumentation/jmx/jmx-engine/library/build.gradle.kts b/instrumentation/jmx/jmx-engine/library/build.gradle.kts new file mode 100644 index 000000000000..399a2611f59b --- /dev/null +++ b/instrumentation/jmx/jmx-engine/library/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("otel.library-instrumentation") +} + +dependencies { + + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") + + testImplementation(project(":testing-common")) +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeInfo.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java similarity index 95% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeInfo.java rename to instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java index 39990a75ee56..01b68bb13869 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeInfo.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; /** * A class holding relevant information about an MBean attribute which will be used for collecting diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeValueExtractor.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java similarity index 93% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeValueExtractor.java rename to instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java index d526d8d634e7..24a6ad35176b 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeValueExtractor.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; import static java.util.logging.Level.FINE; import static java.util.logging.Level.INFO; @@ -23,6 +23,9 @@ * immutable. */ public class AttributeValueExtractor implements LabelExtractor { + + private static final Logger logger = Logger.getLogger(AttributeValueExtractor.class.getName()); + // The attribute name to be used during value extraction from MBean private final String baseName; @@ -95,9 +98,8 @@ String getAttributeName() { * @return AttributeInfo if the attribute is properly recognized, or null */ AttributeInfo getAttributeInfo(MBeanServer server, ObjectName objectName) { - if (MetricService.logger.isLoggable(FINE)) { - MetricService.logger.log( - FINE, "Resolving {0} for {1}", new Object[] {getAttributeName(), objectName}); + if (logger.isLoggable(FINE)) { + logger.log(FINE, "Resolving {0} for {1}", new Object[] {getAttributeName(), objectName}); } try { @@ -119,8 +121,8 @@ AttributeInfo getAttributeInfo(MBeanServer server, ObjectName objectName) { // It is fairly normal to get null values, especially during startup, // but it is much more suspicious to get non-numbers Level logLevel = sampleValue == null ? FINE : INFO; - if (MetricService.logger.isLoggable(logLevel)) { - MetricService.logger.log( + if (logger.isLoggable(logLevel)) { + logger.log( logLevel, "Unusable value {0} for attribute {1} and ObjectName {2}", new Object[] { @@ -134,8 +136,8 @@ AttributeInfo getAttributeInfo(MBeanServer server, ObjectName objectName) { } } - if (MetricService.logger.isLoggable(FINE)) { - MetricService.logger.log( + if (logger.isLoggable(FINE)) { + logger.log( FINE, "Cannot find attribute {0} for ObjectName {1}", new Object[] {baseName, objectName}); @@ -143,9 +145,9 @@ AttributeInfo getAttributeInfo(MBeanServer server, ObjectName objectName) { } catch (InstanceNotFoundException e) { // Should not happen. The ObjectName we use has been provided by the MBeanServer we use. - MetricService.logger.log(INFO, "The MBeanServer does not find {0}", objectName); + logger.log(INFO, "The MBeanServer does not find {0}", objectName); } catch (Exception e) { - MetricService.logger.log( + logger.log( FINE, "Exception {0} while inspecting attributes for ObjectName {1}", new Object[] {e, objectName}); diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanFinder.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java similarity index 98% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanFinder.java rename to instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java index d0f769a0efe0..19e28429e860 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanFinder.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import java.util.ArrayList; diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanPack.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java similarity index 91% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanPack.java rename to instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java index 3bbd7d03c1a9..d0b2143712c8 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/BeanPack.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java @@ -3,14 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; import javax.management.ObjectName; import javax.management.QueryExp; /** * A class describing a set of MBeans which can be used to collect values for a metric. Objects of - * this class are inmutable. + * this class are immutable. */ public class BeanPack { // How to specify the MBean(s) diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/DetectionStatus.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/DetectionStatus.java similarity index 88% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/DetectionStatus.java rename to instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/DetectionStatus.java index 40a78a440b00..e012295fda19 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/DetectionStatus.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/DetectionStatus.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; import java.util.Collection; import javax.management.MBeanServer; @@ -11,7 +11,7 @@ /** * A class encapsulating a set of ObjectNames and the MBeanServer that recognized them. Objects of - * this class are inmutable. + * this class are immutable. */ class DetectionStatus { diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java new file mode 100644 index 000000000000..2f5a513eb156 --- /dev/null +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java @@ -0,0 +1,49 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jmx.engine; + +import static java.util.logging.Level.CONFIG; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import java.util.logging.Logger; + +/** Collecting and exporting JMX metrics. */ +public class JmxMetricInsight { + + private static final Logger logger = Logger.getLogger(JmxMetricInsight.class.getName()); + + private static final String INSTRUMENTATION_SCOPE = "io.opentelemetry.jmx"; + + private final OpenTelemetry openTelemetry; + private final ConfigProperties configProperties; + + public static JmxMetricInsight createService(OpenTelemetry ot, ConfigProperties config) { + return new JmxMetricInsight(ot, config); + } + + public static Logger getLogger() { + return logger; + } + + private JmxMetricInsight(OpenTelemetry ot, ConfigProperties config) { + openTelemetry = ot; + configProperties = config; + } + + public void start(MetricConfiguration conf) { + if (conf.isEmpty()) { + logger.log( + CONFIG, + "Empty JMX configuration, no metrics will be collected for InstrumentationScope " + + INSTRUMENTATION_SCOPE); + } else { + MetricRegistrar registrar = new MetricRegistrar(openTelemetry, INSTRUMENTATION_SCOPE); + BeanFinder finder = new BeanFinder(registrar, configProperties); + finder.discoverBeans(conf); + } + } +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/LabelExtractor.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java similarity index 86% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/LabelExtractor.java rename to instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java index 967573fa42bd..b31666853b48 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/LabelExtractor.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; import javax.management.MBeanServer; import javax.management.ObjectName; diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricBanner.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java similarity index 92% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricBanner.java rename to instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java index 2c74088729da..57b5c41c421d 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricBanner.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java @@ -3,13 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; /** * A class providing the user visible characteristics (name, type, description and units) of a * metric to be reported with OpenTelemetry. * - *

    Objects of this class are inmutable. + *

    Objects of this class are immutable. */ public class MetricBanner { diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricConfiguration.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricConfiguration.java similarity index 90% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricConfiguration.java rename to instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricConfiguration.java index f1c8c8afc2f6..dee55e6b2ba0 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricConfiguration.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricConfiguration.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; import java.util.ArrayList; import java.util.Collection; diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricDef.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java similarity index 92% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricDef.java rename to instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java index 1380deb32576..3d812a0bc513 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricDef.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java @@ -3,12 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; /** * A class providing a complete definition on how to create an Open Telemetry metric out of the JMX * system: how to extract values from MBeans and how to model, name and label them using - * OpenTelemetry Metric API. Objects of this class are inmutable. + * OpenTelemetry Metric API. Objects of this class are immutable. * *

    Example: The JVM provides an MBean with ObjectName "java.lang:type=Threading", and one of the * MBean attributes is "ThreadCount". This MBean can be used to provide a metric showing the current diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricExtractor.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java similarity index 95% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricExtractor.java rename to instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java index 70ae816e9474..0b43df732b00 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricExtractor.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; /** * A class holding the info needed to support a single metric: how to define it in OpenTelemetry and diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricLabel.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java similarity index 92% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricLabel.java rename to instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java index 1cce4a01eb6b..27083ce104cc 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricLabel.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; import javax.management.MBeanServer; import javax.management.ObjectName; @@ -11,7 +11,7 @@ /** * A class representing a metric attribute (label). It is responsible for extracting a label value * (to be reported as a Measurement attribute), and for holding the corresponding label name to be - * used. Objects of this class are inmutable. + * used. Objects of this class are immutable. */ public class MetricLabel { private final String labelName; diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricRegistrar.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java similarity index 94% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricRegistrar.java rename to instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java index 461839b4de75..d67e1256f1f1 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricRegistrar.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; import static java.util.logging.Level.CONFIG; @@ -18,12 +18,15 @@ import io.opentelemetry.api.metrics.ObservableLongMeasurement; import java.util.Collection; import java.util.function.Consumer; +import java.util.logging.Logger; import javax.management.MBeanServer; import javax.management.ObjectName; /** A class responsible for maintaining the set of metrics to collect and report. */ class MetricRegistrar { + private static final Logger logger = Logger.getLogger(MetricRegistrar.class.getName()); + private final Meter meter; MetricRegistrar(OpenTelemetry openTelemetry, String instrumentationScope) { @@ -80,7 +83,7 @@ void enrollExtractor( } else { builder.buildWithCallback(longTypeCallback(extractor)); } - MetricService.logger.log(CONFIG, "Created Counter for {0}", metricName); + logger.log(CONFIG, "Created Counter for {0}", metricName); } break; @@ -101,7 +104,7 @@ void enrollExtractor( } else { builder.buildWithCallback(longTypeCallback(extractor)); } - MetricService.logger.log(CONFIG, "Created UpDownCounter for {0}", metricName); + logger.log(CONFIG, "Created UpDownCounter for {0}", metricName); } break; @@ -122,7 +125,7 @@ void enrollExtractor( } else { builder.ofLongs().buildWithCallback(longTypeCallback(extractor)); } - MetricService.logger.log(CONFIG, "Created Gauge for {0}", metricName); + logger.log(CONFIG, "Created Gauge for {0}", metricName); } } } diff --git a/instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeExtractorTest.java b/instrumentation/jmx/jmx-engine/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java similarity index 99% rename from instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeExtractorTest.java rename to instrumentation/jmx/jmx-engine/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java index 272e7def86ef..249d9243224a 100644 --- a/instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/AttributeExtractorTest.java +++ b/instrumentation/jmx/jmx-engine/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; import static org.assertj.core.api.Assertions.assertThat; diff --git a/instrumentation/jmx/jmx-yaml/library/build.gradle.kts b/instrumentation/jmx/jmx-yaml/library/build.gradle.kts new file mode 100644 index 000000000000..7dd35d0e9e8c --- /dev/null +++ b/instrumentation/jmx/jmx-yaml/library/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("otel.library-instrumentation") +} + +dependencies { + implementation("org.yaml:snakeyaml") + implementation(project(":instrumentation:jmx:jmx-engine:library")) + + testImplementation(project(":testing-common")) +} diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxConfig.java b/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java similarity index 83% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxConfig.java rename to instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java index f79f9d02a609..1749a098310c 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxConfig.java +++ b/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java @@ -3,10 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data; +package io.opentelemetry.instrumentation.jmx.yaml; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricConfiguration; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricDef; +import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration; +import io.opentelemetry.instrumentation.jmx.engine.MetricDef; import java.util.List; /** diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxRule.java b/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java similarity index 91% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxRule.java rename to instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java index a18694c584ed..10dd9ac96731 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/JmxRule.java +++ b/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java @@ -3,14 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data; - -import io.opentelemetry.instrumentation.runtimemetrics.jmx.AttributeValueExtractor; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.BeanPack; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricBanner; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricDef; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricExtractor; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricLabel; +package io.opentelemetry.instrumentation.jmx.yaml; + +import io.opentelemetry.instrumentation.jmx.engine.AttributeValueExtractor; +import io.opentelemetry.instrumentation.jmx.engine.BeanPack; +import io.opentelemetry.instrumentation.jmx.engine.MetricBanner; +import io.opentelemetry.instrumentation.jmx.engine.MetricDef; +import io.opentelemetry.instrumentation.jmx.engine.MetricExtractor; +import io.opentelemetry.instrumentation.jmx.engine.MetricLabel; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -94,10 +94,10 @@ public void setMapping(Map mapping) { } private static Map validateAttributeMapping(Map mapping) { - if (mapping.isEmpty()) { throw new IllegalStateException("No MBean attributes specified"); } + // Make sure that all attribute names are well-formed by creating the corresponding // AttributeValueExtractors Set attrNames = mapping.keySet(); diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/Metric.java b/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java similarity index 91% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/Metric.java rename to instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java index 10bdcdec0098..9d5966c052f4 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/Metric.java +++ b/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java @@ -3,9 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data; +package io.opentelemetry.instrumentation.jmx.yaml; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricBanner; +import io.opentelemetry.instrumentation.jmx.engine.MetricBanner; /** * A class representing metric definition as a part of YAML metric rule. Objects of this class are diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/MetricStructure.java b/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java similarity index 94% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/MetricStructure.java rename to instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java index c546d90a3a14..4cc2a03b70f2 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/data/MetricStructure.java +++ b/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java @@ -3,10 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data; +package io.opentelemetry.instrumentation.jmx.yaml; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricBanner; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricLabel; +import io.opentelemetry.instrumentation.jmx.engine.MetricBanner; +import io.opentelemetry.instrumentation.jmx.engine.MetricLabel; import java.util.ArrayList; import java.util.List; import java.util.Map; diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/yaml/RuleParser.java b/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java similarity index 85% rename from instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/yaml/RuleParser.java rename to instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java index 7ccd418b2de9..d200db1a9537 100644 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/conf/yaml/RuleParser.java +++ b/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java @@ -3,13 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.yaml; +package io.opentelemetry.instrumentation.jmx.yaml; import static java.util.logging.Level.CONFIG; import static java.util.logging.Level.WARNING; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricConfiguration; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data.JmxConfig; +import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration; import java.io.InputStream; import java.util.logging.Logger; import org.yaml.snakeyaml.Yaml; @@ -31,12 +30,11 @@ public class RuleParser { // classes we skip explicit checks for nullnes in the field setters, and let the setters // crash with NullPointerException instead. - private static RuleParser theParser = null; + private static final Logger logger = Logger.getLogger(RuleParser.class.getName()); + + private static final RuleParser theParser = new RuleParser(); public static RuleParser get() { - if (theParser == null) { - theParser = new RuleParser(); - } return theParser; } @@ -51,11 +49,10 @@ public JmxConfig loadConfig(InputStream is) throws Exception { * Parse the YAML rules from the specified input stream and add them, after converting to the * internal representation, to the provided metric configuration. * - * @param logger logger to be used for any messages * @param conf the metric configuration * @param is the InputStream with the YAML rules */ - public void addMetricDefs(Logger logger, MetricConfiguration conf, InputStream is) { + public void addMetricDefs(MetricConfiguration conf, InputStream is) { try { JmxConfig config = loadConfig(is); diff --git a/instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/RuleParserTest.java b/instrumentation/jmx/jmx-yaml/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java similarity index 97% rename from instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/RuleParserTest.java rename to instrumentation/jmx/jmx-yaml/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java index 3d145c4010f2..d8bdc2dd1393 100644 --- a/instrumentation/runtime-metrics/library/src/test/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/RuleParserTest.java +++ b/instrumentation/jmx/jmx-yaml/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java @@ -3,14 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.runtimemetrics.jmx; +package io.opentelemetry.instrumentation.jmx.engine; + +// This test is put in the io.opentelemetry.instrumentation.jmx.engine package +// because it needs to access package-private methods from a number of classes. import static org.assertj.core.api.Assertions.assertThat; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data.JmxConfig; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data.JmxRule; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.data.Metric; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.yaml.RuleParser; +import io.opentelemetry.instrumentation.jmx.yaml.JmxConfig; +import io.opentelemetry.instrumentation.jmx.yaml.JmxRule; +import io.opentelemetry.instrumentation.jmx.yaml.Metric; +import io.opentelemetry.instrumentation.jmx.yaml.RuleParser; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.nio.charset.Charset; diff --git a/instrumentation/runtime-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/RuntimeMetricsInstaller.java b/instrumentation/runtime-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/RuntimeMetricsInstaller.java index fe01ce23d757..025e2298d04a 100644 --- a/instrumentation/runtime-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/RuntimeMetricsInstaller.java +++ b/instrumentation/runtime-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/RuntimeMetricsInstaller.java @@ -14,7 +14,6 @@ import io.opentelemetry.instrumentation.runtimemetrics.GarbageCollector; import io.opentelemetry.instrumentation.runtimemetrics.MemoryPools; import io.opentelemetry.instrumentation.runtimemetrics.Threads; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.MetricService; import io.opentelemetry.javaagent.extension.AgentListener; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -28,25 +27,21 @@ public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { ConfigProperties config = autoConfiguredSdk.getConfig(); boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); - if (config.getBoolean("otel.instrumentation.runtime-metrics.enabled", defaultEnabled)) { - - OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); + if (!config.getBoolean("otel.instrumentation.runtime-metrics.enabled", defaultEnabled)) { + return; + } - BufferPools.registerObservers(openTelemetry); - Classes.registerObservers(openTelemetry); - Cpu.registerObservers(openTelemetry); - MemoryPools.registerObservers(openTelemetry); - Threads.registerObservers(openTelemetry); + OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); - if (config.getBoolean( - "otel.instrumentation.runtime-metrics.experimental-metrics.enabled", false)) { - GarbageCollector.registerObservers(openTelemetry); - } - } + BufferPools.registerObservers(openTelemetry); + Classes.registerObservers(openTelemetry); + Cpu.registerObservers(openTelemetry); + MemoryPools.registerObservers(openTelemetry); + Threads.registerObservers(openTelemetry); - if (config.getBoolean("otel.jmx.enabled", true)) { - MetricService service = new MetricService(GlobalOpenTelemetry.get(), config); - service.start(); + if (config.getBoolean( + "otel.instrumentation.runtime-metrics.experimental-metrics.enabled", false)) { + GarbageCollector.registerObservers(openTelemetry); } } } diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricService.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricService.java deleted file mode 100644 index 8599adc7b6ae..000000000000 --- a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/jmx/MetricService.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.runtimemetrics.jmx; - -import static java.util.logging.Level.CONFIG; -import static java.util.logging.Level.FINE; - -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.instrumentation.runtimemetrics.jmx.conf.yaml.RuleParser; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; -import java.io.File; -import java.io.InputStream; -import java.nio.file.Files; -import java.util.logging.Logger; - -/** Collecting and exporting JMX metrics. */ -public class MetricService { - - static final Logger logger = Logger.getLogger("JMX Metric Insight"); - - private static final String INSTRUMENTATION_SCOPE = "io.opentelemetry.jmx"; - - private final OpenTelemetry openTelemetry; - private final ConfigProperties configProperties; - - public MetricService(OpenTelemetry ot, ConfigProperties config) { - openTelemetry = ot; - configProperties = config; - } - - private static String resourceFor(String platform) { - return "/jmx/rules/" + platform + ".yaml"; - } - - private void addRulesForPlatform(String platform, MetricConfiguration conf) { - - String yamlResource = resourceFor(platform); - try (InputStream inputStream = getClass().getResourceAsStream(yamlResource)) { - if (inputStream != null) { - logger.log(FINE, "Opened input stream {0}", yamlResource); - RuleParser parserInstance = RuleParser.get(); - parserInstance.addMetricDefs(logger, conf, inputStream); - } else { - logger.log(CONFIG, "No support found for {0}", platform); - } - } catch (Exception e) { - logger.warning(e.getMessage()); - } - } - - private void buildFromDefaultRules(MetricConfiguration conf) { - - String targetSystem = System.getProperty("otel.jmx.target.system", "").trim(); - String[] platforms = targetSystem.length() == 0 ? new String[0] : targetSystem.split(","); - - for (String platform : platforms) { - addRulesForPlatform(platform, conf); - } - } - - private static void buildFromUserRules(MetricConfiguration conf) { - String jmxDir = System.getProperty("otel.jmx.config"); - if (jmxDir != null) { - logger.log(CONFIG, "JMX config file name: {0}", jmxDir); - RuleParser parserInstance = RuleParser.get(); - try (InputStream inputStream = Files.newInputStream(new File(jmxDir.trim()).toPath())) { - parserInstance.addMetricDefs(logger, conf, inputStream); - } catch (Exception e) { - logger.warning(e.getMessage()); - } - } - } - - private MetricConfiguration buildMetricConfiguration() { - MetricConfiguration conf = new MetricConfiguration(); - - buildFromDefaultRules(conf); - - buildFromUserRules(conf); - - return conf; - } - - public void start() { - MetricConfiguration conf = buildMetricConfiguration(); - - if (conf.isEmpty()) { - logger.log( - CONFIG, - "Empty JMX configuration, no metrics will be collected for InstrumentationScope " - + INSTRUMENTATION_SCOPE); - } else { - MetricRegistrar registrar = new MetricRegistrar(openTelemetry, INSTRUMENTATION_SCOPE); - BeanFinder finder = new BeanFinder(registrar, configProperties); - finder.discoverBeans(conf); - } - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index e991b837ca47..39df775d853e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -298,6 +298,9 @@ include(":instrumentation:jetty-httpclient:jetty-httpclient-9.2:library") include(":instrumentation:jetty-httpclient:jetty-httpclient-9.2:testing") include(":instrumentation:jms-1.1:javaagent") include(":instrumentation:jms-1.1:javaagent-unit-tests") +include(":instrumentation:jmx:javaagent") +include(":instrumentation:jmx:jmx-engine:library") +include(":instrumentation:jmx:jmx-yaml:library") include(":instrumentation:jsf:jsf-common:javaagent") include(":instrumentation:jsf:jsf-common:testing") include(":instrumentation:jsf:jsf-mojarra-1.2:javaagent") From 0ca7a0d9957d10b571755f8f2a0a31de28701521 Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Wed, 28 Sep 2022 10:34:29 -0700 Subject: [PATCH 06/20] Cleanup in runtime-metrics. --- instrumentation/runtime-metrics/library/build.gradle.kts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/instrumentation/runtime-metrics/library/build.gradle.kts b/instrumentation/runtime-metrics/library/build.gradle.kts index 24a033152053..34d3651cdc0a 100644 --- a/instrumentation/runtime-metrics/library/build.gradle.kts +++ b/instrumentation/runtime-metrics/library/build.gradle.kts @@ -3,10 +3,6 @@ plugins { } dependencies { - implementation("org.yaml:snakeyaml") - - compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") - testImplementation("io.opentelemetry:opentelemetry-sdk-metrics") testImplementation(project(":testing-common")) } From 009dff67224c1958ae9f94971ff3c01160a4aa79 Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Tue, 4 Oct 2022 13:18:05 -0700 Subject: [PATCH 07/20] Removing kafka-consumer and kafka-producer metrics from the list of supported platforms. Introducing system property to control time interval between MBean discovery attempts. Code refactoring. --- instrumentation/jmx/javaagent/README.md | 6 +- .../jmx/javaagent/kafka-consumer.md | 28 ------- .../jmx/javaagent/kafka-producer.md | 24 ------ .../jmx/JmxMetricInsightInstaller.java | 15 +++- .../resources/jmx/rules/kafka-consumer.yaml | 80 ------------------- .../resources/jmx/rules/kafka-producer.yaml | 63 --------------- .../jmx/jmx-engine/library/build.gradle.kts | 2 - .../jmx/engine/AttributeValueExtractor.java | 7 +- .../jmx/engine/BeanFinder.java | 12 +-- .../jmx/engine/JmxMetricInsight.java | 15 ++-- 10 files changed, 34 insertions(+), 218 deletions(-) delete mode 100644 instrumentation/jmx/javaagent/kafka-consumer.md delete mode 100644 instrumentation/jmx/javaagent/kafka-producer.md delete mode 100644 instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-consumer.yaml delete mode 100644 instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-producer.yaml diff --git a/instrumentation/jmx/javaagent/README.md b/instrumentation/jmx/javaagent/README.md index 4473e687ba9d..c2c3b3e1e650 100644 --- a/instrumentation/jmx/javaagent/README.md +++ b/instrumentation/jmx/javaagent/README.md @@ -8,13 +8,15 @@ available within the instrumented application. The required MBeans and correspon The selected JMX metrics are reported using the Java Agent internal SDK. This means that they share the configuration and metric exporter with other metrics collected by the agent and are controlled by the same properties, for example `otel.metric.export.interval` or `otel.metrics.exporter`. The Open Telemetry resource description for the metrics reported by JMX Metric Insight will be the same as for other metrics exported by the SDK, while the instrumentation scope will be `io.opentelemetry.jmx`. +To control the time interval between MBean detection attempts, one can use the `otel.jmx.discovery.delay` property, which defines the number of milliseconds to elapse between the first and the next detection cycle. JMX Metric Insight may dynamically adjust the time interval between further attempts, but it guarantees that the MBean discovery will run perpetually. + ## Predefined metrics JMX Metric Insight comes with a number of predefined configurations containing curated sets of JMX metrics for popular application servers or frameworks. To enable collection for the predefined metrics, specify a list of targets as the value for the `otel.jmx.target.system` property. For example ```bash $ java -javaagent:path/to/opentelemetry-javaagent.jar \ - -Dotel.jmx.target.system=kafka-broker,kafka-consumer \ + -Dotel.jmx.target.system=jetty,kafka-broker \ ... \ -jar myapp.jar ``` @@ -24,8 +26,6 @@ No targets are enabled by default. The supported target environments are listed - [activemq](activemq.md) - [jetty](jetty.md) - [kafka-broker](kafka-broker.md) - - [kafka-consumer](kafka-consumer.md) - - [kafka-producer](kafka-producer.md) - [tomcat](tomcat.md) - [wildfly](wildfly.md) - [hadoop](hadoop.md) diff --git a/instrumentation/jmx/javaagent/kafka-consumer.md b/instrumentation/jmx/javaagent/kafka-consumer.md deleted file mode 100644 index c591ac6e0bac..000000000000 --- a/instrumentation/jmx/javaagent/kafka-consumer.md +++ /dev/null @@ -1,28 +0,0 @@ -# Kafka Consumer Metrics - -Here is the list of metrics based on MBeans exposed by Kafka consumer.

    - -Consumer metrics: - -| Metric Name | Type | Attributes | Description | -|---------------------------------------------------|-------|------------------|--------------------------------------------------------------------------------| -| kafka.consumer.all.rebalance-latency-avg | Gauge | client-id | The average time taken for a group to complete a successful rebalance | -| kafka.consumer.all.rebalance-latency-max | Gauge | client-id | The maximum time taken for a group to complete a successful rebalance | -| kafka.consumer.all.rebalance-latency-total | Gauge | client-id | The total time this consumer has spent in successful rebalances since creation | -| kafka.consumer.all.rebalance-rate-per-hour | Gauge | client-id | The number of successful rebalance events per hour | -| kafka.consumer.all.rebalance-total | Gauge | client-id | The total number of successful rebalance events | -| kafka.consumer.all.last-rebalance-seconds-ago | Gauge | client-id | Number of seconds since the last rebalance event | -| kafka.consumer.all.failed-rebalance-rate-per-hour | Gauge | client-id | Number of failed rebalance events per hour | -| kafka.consumer.all.failed-rebalance-total | Gauge | client-id | Total number of failed rebalance events | -| kafka.consumer.all.commit-latency-avg | Gauge | client-id | The average time taken for a commit request | -| kafka.consumer.all.commit-rate | Gauge | client-id | The number of commit calls per second | -| kafka.consumer.all.fetch-rate | Gauge | client-id | The number of fetch requests for all topics per second | -| kafka.consumer.all.fetch-size-avg | Gauge | client-id | The average number of bytes fetched per request for all topics | -| kafka.consumer.all.fetch-latency-avg | Gauge | client-id | The average time taken for a fetch request | -| kafka.consumer.all.fetch-throttle-time-avg | Gauge | client-id | The average throttle time | -| kafka.consumer.all.records-lag-max | Gauge | client-id | Number of messages the consumer lags behind the producer | -| kafka.consumer.all.records-consumed-rate | Gauge | client-id | The average number of records consumed for all topics per second | -| kafka.consumer.all.bytes-consumed-rate | Gauge | client-id | The average number of bytes consumed for all topics per second | -| kafka.consumer.bytes-consumed-rate | Gauge | client-id, topic | The average number of bytes consumed per second | -| kafka.consumer.fetch-size-avg | Gauge | client-id, topic | The average number of bytes fetched per request | -| kafka.consumer.records-consumed-rate | Gauge | client-id, topic | The average number of records consumed per second | diff --git a/instrumentation/jmx/javaagent/kafka-producer.md b/instrumentation/jmx/javaagent/kafka-producer.md deleted file mode 100644 index 850bc4db0cc2..000000000000 --- a/instrumentation/jmx/javaagent/kafka-producer.md +++ /dev/null @@ -1,24 +0,0 @@ -# Kafka Producer Metrics - -Here is the list of metrics based on MBeans exposed by Kafka producer.

    - -Producer metrics: - -| Metric Name | Type | Attributes | Description | -|----------------------------------------------|-------|------------------|--------------------------------------------------------------------------------------| -| kafka.producer.all.batch-size-avg | Gauge | client-id | Average number of bytes sent per partition per request | -| kafka.producer.all.bufferpool-wait-ratio | Gauge | client-id | The fraction of time an appender waits for space allocation | -| kafka.producer.all.compression-rate-avg | Gauge | client-id | Average ratio of the compressed batch size to the uncompressed size | -| kafka.producer.all.io-wait-time-ns-avg | Gauge | client-id | The average time the I/O thread spent waiting for a socket ready for reads or writes | -| kafka.producer.all.outgoing-byte-rate | Gauge | client-id | The average number of outgoing bytes sent per second to all servers | -| kafka.producer.all.produce-throttle-time-avg | Gauge | client-id | Average time a request was throttled by a broker | -| kafka.producer.all.record-queue-time-avg | Gauge | client-id | The average time record batches spent in the send buffer | -| kafka.producer.all.record-retry-rate | Gauge | client-id | The average number of retried record sends per second | -| kafka.producer.all.request-latency-avg | Gauge | client-id | The average request latency | -| kafka.producer.all.request-rate | Gauge | client-id | The average number of requests sent per second | -| kafka.producer.all.response-rate | Gauge | client-id | The average number of response sent per second | -| kafka.producer.byte-rate | Gauge | client-id, topic | The average number of bytes sent per second for a topic | -| kafka.producer.compression-rate | Gauge | client-id, topic | The average compression rate of record batches for a topic | -| kafka.producer.record-error-rate | Gauge | client-id, topic | The average per-second number of record sends that resulted in errors for a topic | -| kafka.producer.record-retry-rate | Gauge | client-id, topic | The average per-second number of retried record sends for a topic | -| kafka.producer.record-send-rate | Gauge | client-id, topic | The average number of records sent per second for a topic | diff --git a/instrumentation/jmx/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java b/instrumentation/jmx/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java index 6b365c6bffb4..9abea4288e6d 100644 --- a/instrumentation/jmx/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java +++ b/instrumentation/jmx/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java @@ -29,12 +29,25 @@ public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { ConfigProperties config = autoConfiguredSdk.getConfig(); if (config.getBoolean("otel.jmx.enabled", true)) { - JmxMetricInsight service = JmxMetricInsight.createService(GlobalOpenTelemetry.get(), config); + JmxMetricInsight service = + JmxMetricInsight.createService(GlobalOpenTelemetry.get(), beanDiscoveryDelay(config)); MetricConfiguration conf = buildMetricConfiguration(); service.start(conf); } } + private static long beanDiscoveryDelay(ConfigProperties configProperties) { + Long discoveryDelay = configProperties.getLong("otel.jmx.discovery.delay"); + if (discoveryDelay != null) { + return discoveryDelay; + } + + // If discovery delay has not been configured, have a peek at the metric export interval. + // It makes sense for both of these values to be similar. + long exportInterval = configProperties.getLong("otel.metric.export.interval", 60000); + return exportInterval; + } + private static String resourceFor(String platform) { return "/jmx/rules/" + platform + ".yaml"; } diff --git a/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-consumer.yaml b/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-consumer.yaml deleted file mode 100644 index c5d5556657ec..000000000000 --- a/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-consumer.yaml +++ /dev/null @@ -1,80 +0,0 @@ ---- -rules: - # Consumer metrics - - - bean: kafka.consumer:client-id=*,type=consumer-coordinator-metrics - label: - client-id: param(client-id) - prefix: kafka.consumer.all. - type: gauge - unit: 1 - mapping: - rebalance-latency-avg: - desc: The average time taken for a group to complete a successful rebalance - unit: ms - rebalance-latency-max: - desc: The maximum time taken for a group to complete a successful rebalance - unit: ms - rebalance-latency-total: - desc: The total time this consumer has spent in successful rebalances since creation - unit: ms - rebalance-rate-per-hour: - desc: The number of successful rebalance events per hour - rebalance-total: - desc: The total number of successful rebalance events - last-rebalance-seconds-ago: - desc: Number of seconds since the last rebalance event - unit: s - failed-rebalance-rate-per-hour: - desc: Number of failed rebalance events per hour - failed-rebalance-total: - desc: Total number of failed rebalance events - commit-latency-avg: - desc: The average time taken for a commit request - unit: ms - commit-rate: - desc: The number of commit calls per second - - - bean: kafka.consumer:client-id=*,type=consumer-fetch-manager-metrics - label: - client-id: param(client-id) - prefix: kafka.consumer.all. - type: gauge - unit: 1 - mapping: - fetch-rate: - desc: The number of fetch requests for all topics per second - fetch-size-avg: - desc: The average number of bytes fetched per request for all topics - unit: By - fetch-latency-avg: - desc: The average time taken for a fetch request - unit: ms - fetch-throttle-time-avg: - desc: The average throttle time - unit: ms - records-lag-max: - desc: Number of messages the consumer lags behind the producer - records-consumed-rate: - desc: The average number of records consumed for all topics per second - bytes-consumed-rate: - desc: The average number of bytes consumed for all topics per second - unit: By - - # Per-topic consumer metrics - - - bean: kafka.consumer:client-id=*,topic=*,type=consumer-fetch-manager-metrics - label: - client-id: param(client-id) - topic: param(topic) - prefix: kafka.consumer. - type: gauge - unit: By - mapping: - bytes-consumed-rate: - desc: The average number of bytes consumed per second - fetch-size-avg: - desc: The average number of bytes fetched per request - records-consumed-rate: - desc: The average number of records consumed per second - unit: 1 \ No newline at end of file diff --git a/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-producer.yaml b/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-producer.yaml deleted file mode 100644 index b7739f07a1e0..000000000000 --- a/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-producer.yaml +++ /dev/null @@ -1,63 +0,0 @@ ---- -rules: - # Producer metrics - - - bean: kafka.producer:client-id=*,type=producer-metrics - label: - client-id: param(client-id) - prefix: kafka.producer.all. - type: gauge - unit: 1 - mapping: - batch-size-avg: - desc: Average number of bytes sent per partition per request - unit: By - bufferpool-wait-ratio: - desc: The fraction of time an appender waits for space allocation - compression-rate-avg: - desc: Average ratio of the compressed batch size to the uncompressed size - io-wait-time-ns-avg: - desc: The average time the I/O thread spent waiting for a socket ready for reads or writes - unit: ns - outgoing-byte-rate: - desc: The average number of outgoing bytes sent per second to all servers - unit: By - produce-throttle-time-avg: - desc: Average time a request was throttled by a broker - unit: ms - record-queue-time-avg: - desc: The average time record batches spent in the send buffer - unit: ms - record-retry-rate: - desc: The average number of retried record sends per second - request-latency-avg: - desc: The average request latency - unit: ms - request-rate: - desc: The average number of requests sent per second - unit: '{requests}' - response-rate: - desc: The average number of responses received per second - unit: '{responses}' - - # Per-topic Producer metrics - - - bean: kafka.producer:client-id=*,topic=*,type=producer-topic-metrics - label: - client-id: param(client-id) - topic: param(topic) - prefix: kafka.producer. - type: gauge - unit: 1 - mapping: - byte-rate: - desc: The average number of bytes sent per second for a topic - unit: By - compression-rate: - desc: The average compression rate of record batches for a topic - record-error-rate: - desc: The average per-second number of record sends that resulted in errors for a topic - record-retry-rate: - desc: The average per-second number of retried record sends for a topic - record-send-rate: - desc: The average number of records sent per second for a topic diff --git a/instrumentation/jmx/jmx-engine/library/build.gradle.kts b/instrumentation/jmx/jmx-engine/library/build.gradle.kts index 399a2611f59b..e04e9398ca24 100644 --- a/instrumentation/jmx/jmx-engine/library/build.gradle.kts +++ b/instrumentation/jmx/jmx-engine/library/build.gradle.kts @@ -4,7 +4,5 @@ plugins { dependencies { - compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") - testImplementation(project(":testing-common")) } diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java index 24a6ad35176b..db18fcf01b50 100644 --- a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java @@ -41,12 +41,13 @@ public class AttributeValueExtractor implements LabelExtractor { * @throws IllegalArgumentException if the attribute name is malformed */ public static AttributeValueExtractor fromName(String rawName) { + if (rawName.isEmpty()) { + throw new IllegalArgumentException("Empty attribute name"); + } + // Check if a CompositeType value is expected int k = rawName.indexOf('.'); if (k < 0) { - if (rawName.isEmpty()) { - throw new IllegalArgumentException("Empty attribute name"); - } return new AttributeValueExtractor(rawName); } diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java index 19e28429e860..827c32f400bb 100644 --- a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java @@ -5,7 +5,6 @@ package io.opentelemetry.instrumentation.jmx.engine; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -26,14 +25,14 @@ class BeanFinder { private final MetricRegistrar registrar; private MetricConfiguration conf; private final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); - private final long exportInterval; + private final long discoveryDelay; private final long maxDelay; private long delay = 1000; // number of milliseconds until first attempt to discover MBeans - BeanFinder(MetricRegistrar registrar, ConfigProperties configProperties) { + BeanFinder(MetricRegistrar registrar, long discoveryDelay) { this.registrar = registrar; - this.exportInterval = configProperties.getLong("otel.metric.export.interval", 60000); - this.maxDelay = Math.max(60000, exportInterval); + this.discoveryDelay = Math.max(1000, discoveryDelay); // Enforce sanity + this.maxDelay = Math.max(60000, discoveryDelay); } void discoverBeans(MetricConfiguration conf) { @@ -44,7 +43,8 @@ void discoverBeans(MetricConfiguration conf) { @Override public void run() { refreshState(); - delay = Math.min(delay + exportInterval, maxDelay); + // Use discoveryDelay as the increment for the actual delay + delay = Math.min(delay + discoveryDelay, maxDelay); exec.schedule(this, delay, TimeUnit.MILLISECONDS); } }, diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java index 2f5a513eb156..3a6b82f484de 100644 --- a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java +++ b/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java @@ -8,7 +8,6 @@ import static java.util.logging.Level.CONFIG; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import java.util.logging.Logger; /** Collecting and exporting JMX metrics. */ @@ -19,19 +18,19 @@ public class JmxMetricInsight { private static final String INSTRUMENTATION_SCOPE = "io.opentelemetry.jmx"; private final OpenTelemetry openTelemetry; - private final ConfigProperties configProperties; + private final long discoveryDelay; - public static JmxMetricInsight createService(OpenTelemetry ot, ConfigProperties config) { - return new JmxMetricInsight(ot, config); + public static JmxMetricInsight createService(OpenTelemetry ot, long discoveryDelay) { + return new JmxMetricInsight(ot, discoveryDelay); } public static Logger getLogger() { return logger; } - private JmxMetricInsight(OpenTelemetry ot, ConfigProperties config) { - openTelemetry = ot; - configProperties = config; + private JmxMetricInsight(OpenTelemetry openTelemetry, long discoveryDelay) { + this.openTelemetry = openTelemetry; + this.discoveryDelay = discoveryDelay; } public void start(MetricConfiguration conf) { @@ -42,7 +41,7 @@ public void start(MetricConfiguration conf) { + INSTRUMENTATION_SCOPE); } else { MetricRegistrar registrar = new MetricRegistrar(openTelemetry, INSTRUMENTATION_SCOPE); - BeanFinder finder = new BeanFinder(registrar, configProperties); + BeanFinder finder = new BeanFinder(registrar, discoveryDelay); finder.discoverBeans(conf); } } From b2ea55d0e71468df1a8bcd0a150ede5966374816 Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Wed, 5 Oct 2022 13:25:41 -0700 Subject: [PATCH 08/20] Fixing the issue with always null logger in AttributeValueExtractor. Renaming module 'jmx' to 'jmx-metrics'. Changing the syntax of the metric attributes retrieved from Mbean attributes. Editing docs and comments for better readability. --- .../{jmx => jmx-metrics}/javaagent/README.md | 16 ++++++++-------- .../{jmx => jmx-metrics}/javaagent/activemq.md | 0 .../jmx-metrics/javaagent/build.gradle.kts | 10 ++++++++++ .../{jmx => jmx-metrics}/javaagent/hadoop.md | 0 .../{jmx => jmx-metrics}/javaagent/jetty.md | 0 .../javaagent/kafka-broker.md | 0 .../javaagent/jmx/JmxMetricInsightInstaller.java | 0 .../src/main/resources/jmx/rules/activemq.yaml | 0 .../src/main/resources/jmx/rules/hadoop.yaml | 0 .../src/main/resources/jmx/rules/jetty.yaml | 0 .../main/resources/jmx/rules/kafka-broker.yaml | 0 .../src/main/resources/jmx/rules/tomcat.yaml | 0 .../src/main/resources/jmx/rules/wildfly.yaml | 0 .../{jmx => jmx-metrics}/javaagent/tomcat.md | 0 .../{jmx => jmx-metrics}/javaagent/wildfly.md | 0 .../jmx-engine/library/build.gradle.kts | 0 .../jmx/engine/AttributeInfo.java | 0 .../jmx/engine/AttributeValueExtractor.java | 7 +++++-- .../instrumentation/jmx/engine/BeanFinder.java | 0 .../instrumentation/jmx/engine/BeanPack.java | 0 .../jmx/engine/DetectionStatus.java | 0 .../jmx/engine/JmxMetricInsight.java | 0 .../jmx/engine/LabelExtractor.java | 0 .../instrumentation/jmx/engine/MetricBanner.java | 0 .../jmx/engine/MetricConfiguration.java | 0 .../instrumentation/jmx/engine/MetricDef.java | 0 .../jmx/engine/MetricExtractor.java | 0 .../instrumentation/jmx/engine/MetricLabel.java | 0 .../jmx/engine/MetricRegistrar.java | 0 .../jmx/engine/AttributeExtractorTest.java | 0 .../jmx-yaml/library/build.gradle.kts | 2 +- .../instrumentation/jmx/yaml/JmxConfig.java | 0 .../instrumentation/jmx/yaml/JmxRule.java | 0 .../instrumentation/jmx/yaml/Metric.java | 0 .../jmx/yaml/MetricStructure.java | 6 +++--- .../instrumentation/jmx/yaml/RuleParser.java | 0 .../jmx/engine/RuleParserTest.java | 10 +++++----- instrumentation/jmx/javaagent/build.gradle.kts | 10 ---------- settings.gradle.kts | 6 +++--- 39 files changed, 35 insertions(+), 32 deletions(-) rename instrumentation/{jmx => jmx-metrics}/javaagent/README.md (92%) rename instrumentation/{jmx => jmx-metrics}/javaagent/activemq.md (100%) create mode 100644 instrumentation/jmx-metrics/javaagent/build.gradle.kts rename instrumentation/{jmx => jmx-metrics}/javaagent/hadoop.md (100%) rename instrumentation/{jmx => jmx-metrics}/javaagent/jetty.md (100%) rename instrumentation/{jmx => jmx-metrics}/javaagent/kafka-broker.md (100%) rename instrumentation/{jmx => jmx-metrics}/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java (100%) rename instrumentation/{jmx => jmx-metrics}/javaagent/src/main/resources/jmx/rules/activemq.yaml (100%) rename instrumentation/{jmx => jmx-metrics}/javaagent/src/main/resources/jmx/rules/hadoop.yaml (100%) rename instrumentation/{jmx => jmx-metrics}/javaagent/src/main/resources/jmx/rules/jetty.yaml (100%) rename instrumentation/{jmx => jmx-metrics}/javaagent/src/main/resources/jmx/rules/kafka-broker.yaml (100%) rename instrumentation/{jmx => jmx-metrics}/javaagent/src/main/resources/jmx/rules/tomcat.yaml (100%) rename instrumentation/{jmx => jmx-metrics}/javaagent/src/main/resources/jmx/rules/wildfly.yaml (100%) rename instrumentation/{jmx => jmx-metrics}/javaagent/tomcat.md (100%) rename instrumentation/{jmx => jmx-metrics}/javaagent/wildfly.md (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/build.gradle.kts (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java (95%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/DetectionStatus.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricConfiguration.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-engine/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-yaml/library/build.gradle.kts (66%) rename instrumentation/{jmx => jmx-metrics}/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java (97%) rename instrumentation/{jmx => jmx-metrics}/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java (100%) rename instrumentation/{jmx => jmx-metrics}/jmx-yaml/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java (98%) delete mode 100644 instrumentation/jmx/javaagent/build.gradle.kts diff --git a/instrumentation/jmx/javaagent/README.md b/instrumentation/jmx-metrics/javaagent/README.md similarity index 92% rename from instrumentation/jmx/javaagent/README.md rename to instrumentation/jmx-metrics/javaagent/README.md index c2c3b3e1e650..75f8788e79ef 100644 --- a/instrumentation/jmx/javaagent/README.md +++ b/instrumentation/jmx-metrics/javaagent/README.md @@ -96,7 +96,7 @@ rules: - bean: java.lang:name=*,type=MemoryPool label: pool: param(name) - type: attrib(Type) + type: attr(Type) mapping: Usage.used: metric: my.own.jvm.memory.pool.used @@ -110,7 +110,7 @@ rules: unit: By ``` -The ObjectName pattern will match a number of MBeans, each for a different memory pool. The number and names of available memory pools, however, will be known only at runtime. To report values for all actual memory pools using only two metrics, we use metric attributes (referenced by the configuration file as `label`s). The first metric attribute, named `pool` will have its value derived from the ObjectName parameter `name` - which corresponds to the memory pool name. The second metric attribute, named `type` will get its value from the corresponding MBean attribute named `Type`. The values of this attribute are strings `HEAP` or `NON_HEAP` classifying the corresponding memory pool. Here the definition of the metric attributes is shared by both metrics, but it is also possible to define them at the individual metric level. +The ObjectName pattern will match a number of MBeans, each for a different memory pool. The number and names of available memory pools, however, will be known only at runtime. To report values for all actual memory pools using only two metrics, we use metric attributes (referenced by the configuration file as `label` elements). The first metric attribute, named `pool` will have its value derived from the ObjectName parameter `name` - which corresponds to the memory pool name. The second metric attribute, named `type` will get its value from the corresponding MBean attribute named `Type`. The values of this attribute are strings `HEAP` or `NON_HEAP` classifying the corresponding memory pool. Here the definition of the metric attributes is shared by both metrics, but it is also possible to define them at the individual metric level. Using the above rule, when running on HotSpot JVM for Java 11, the following combinations of metric attributes will be reported. - {pool="Compressed Class Space", type="NON_HEAP"} @@ -154,7 +154,7 @@ The referenced MBean has two attributes of interest, `bytesReceived`, and `bytes Keep in mind that when defining a metric multiple times like this, its type, unit and description must be exactly the same. Otherwise there will be complaints about attempts to redefine a metric in a non-compatible way. The example also demonstrates that when specifying a number of MBean attribute mappings within the same rule, the metric type can be declared only once (outside of the `mapping` section). -Even when not reusing the metric name, special care also has to be taken when using ObjectName patterns (or specifying multiple ObjectNames). Different ObjectNames matching the pattern must result in using different metric attributes. Otherwise the same metric will be reported multiple times (using different values), which will likely clobber the previous values. +Even when not reusing the metric name, special care also has to be taken when using ObjectName patterns (or specifying multiple ObjectNames - see the General Syntax section at the bottom of the page). Different ObjectNames matching the pattern must result in using different metric attributes. Otherwise the same metric will be reported multiple times (using different values), which will likely clobber the previous values. ### Making shortcuts @@ -211,7 +211,7 @@ Thus, the above definitions will create several metrics, named `my.kafka.streams The metric descriptions will remain undefined, unless they are provided by the queried MBeans. -### General syntax +### General Syntax Here is the general description of the accepted configuration file syntax. The whole contents of the file is case-sensitive, with exception for `type` as described in the table below. @@ -221,7 +221,7 @@ rules: # start of list of configuration rules - bean: # can contain wildcards label: # optional metric attributes, they apply to all metrics below : param() # is used as the key to extract value from actual ObjectName - : attrib() # is used as the attribute name to extract value from MBean + : attr() # is used as the attribute name to extract value from MBean prefix: # optional, useful for avoiding specifying metric names below unit: # optional, redefines the default unit for the whole rule type: # optional, redefines the default type for the whole rule @@ -251,9 +251,9 @@ The following table explains the used terms with more details. | Syntactic Element | Description | | ---------------- | --------------- | -| OBJECTNAME | A syntactically valid string representing an ObjectName (see [ObjectName constructor](https://docs.oracle.com/javase/8/docs/api/javax/management/ObjectName.html#ObjectName-java.lang.String-) ). | +| OBJECTNAME | A syntactically valid string representing an ObjectName (see [ObjectName constructor](https://docs.oracle.com/javase/8/docs/api/javax/management/ObjectName.html#ObjectName-java.lang.String-)). | | LABEL | Any well-formed string that can be used as a metric [attribute](https://opentelemetry.io/docs/reference/specification/common/#attribute) key. | -| ATTRIB | A non-empty string used as a name of the MBean attribute. The attribute value must be a String, otherwise the specified label (metric attribute) will not be used. | +| ATTR | A non-empty string used as a name of the MBean attribute. The attribute value must be a String, otherwise the specified label (metric attribute) will not be used. | | PARAM | A non-empty string used as a property key for the ObjectName identifying the MBean which provides the metric value. If the ObjectName does not have a property with the given key, the specified label will not be used. | | METRIC_NAME_PREFIX | Any non-empty string which will be prepended to the specified metric (instrument) names. | | METRIC_NAME | Any non-empty string. The string, prefixed by the optional prefix (see above) must satisfy [instrument naming rule](https://opentelemetry.io/docs/reference/specification/metrics/api/#instrument-naming-rule). | @@ -267,6 +267,6 @@ The following table explains the used terms with more details. This version of JMX Metric Insight has a number of limitations. -- Attributes with the same name but belonging to different MBeans described by a single metric rule must have the same type (long or double). +- MBean attributes with the same name but belonging to different MBeans described by a single metric rule must have the same type (long or double). - All MBeans which are described by the specified ObjectNames in a single rule must be registered with the same MBeanServer instance. - While MBeanServers and MBeans can be created dynamically by the application, it is assumed that they will live indefinitely. Their disappearance may not be recognized properly, and may lead to some memory leaks. diff --git a/instrumentation/jmx/javaagent/activemq.md b/instrumentation/jmx-metrics/javaagent/activemq.md similarity index 100% rename from instrumentation/jmx/javaagent/activemq.md rename to instrumentation/jmx-metrics/javaagent/activemq.md diff --git a/instrumentation/jmx-metrics/javaagent/build.gradle.kts b/instrumentation/jmx-metrics/javaagent/build.gradle.kts new file mode 100644 index 000000000000..84d770745ffe --- /dev/null +++ b/instrumentation/jmx-metrics/javaagent/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +dependencies { + implementation(project(":instrumentation:jmx-metrics:jmx-engine:library")) + implementation(project(":instrumentation:jmx-metrics:jmx-yaml:library")) + + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") +} diff --git a/instrumentation/jmx/javaagent/hadoop.md b/instrumentation/jmx-metrics/javaagent/hadoop.md similarity index 100% rename from instrumentation/jmx/javaagent/hadoop.md rename to instrumentation/jmx-metrics/javaagent/hadoop.md diff --git a/instrumentation/jmx/javaagent/jetty.md b/instrumentation/jmx-metrics/javaagent/jetty.md similarity index 100% rename from instrumentation/jmx/javaagent/jetty.md rename to instrumentation/jmx-metrics/javaagent/jetty.md diff --git a/instrumentation/jmx/javaagent/kafka-broker.md b/instrumentation/jmx-metrics/javaagent/kafka-broker.md similarity index 100% rename from instrumentation/jmx/javaagent/kafka-broker.md rename to instrumentation/jmx-metrics/javaagent/kafka-broker.md diff --git a/instrumentation/jmx/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java b/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java similarity index 100% rename from instrumentation/jmx/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java rename to instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java diff --git a/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/activemq.yaml b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/activemq.yaml similarity index 100% rename from instrumentation/jmx/javaagent/src/main/resources/jmx/rules/activemq.yaml rename to instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/activemq.yaml diff --git a/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/hadoop.yaml b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/hadoop.yaml similarity index 100% rename from instrumentation/jmx/javaagent/src/main/resources/jmx/rules/hadoop.yaml rename to instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/hadoop.yaml diff --git a/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/jetty.yaml similarity index 100% rename from instrumentation/jmx/javaagent/src/main/resources/jmx/rules/jetty.yaml rename to instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/jetty.yaml diff --git a/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-broker.yaml b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/kafka-broker.yaml similarity index 100% rename from instrumentation/jmx/javaagent/src/main/resources/jmx/rules/kafka-broker.yaml rename to instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/kafka-broker.yaml diff --git a/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/tomcat.yaml b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/tomcat.yaml similarity index 100% rename from instrumentation/jmx/javaagent/src/main/resources/jmx/rules/tomcat.yaml rename to instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/tomcat.yaml diff --git a/instrumentation/jmx/javaagent/src/main/resources/jmx/rules/wildfly.yaml b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/wildfly.yaml similarity index 100% rename from instrumentation/jmx/javaagent/src/main/resources/jmx/rules/wildfly.yaml rename to instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/wildfly.yaml diff --git a/instrumentation/jmx/javaagent/tomcat.md b/instrumentation/jmx-metrics/javaagent/tomcat.md similarity index 100% rename from instrumentation/jmx/javaagent/tomcat.md rename to instrumentation/jmx-metrics/javaagent/tomcat.md diff --git a/instrumentation/jmx/javaagent/wildfly.md b/instrumentation/jmx-metrics/javaagent/wildfly.md similarity index 100% rename from instrumentation/jmx/javaagent/wildfly.md rename to instrumentation/jmx-metrics/javaagent/wildfly.md diff --git a/instrumentation/jmx/jmx-engine/library/build.gradle.kts b/instrumentation/jmx-metrics/jmx-engine/library/build.gradle.kts similarity index 100% rename from instrumentation/jmx/jmx-engine/library/build.gradle.kts rename to instrumentation/jmx-metrics/jmx-engine/library/build.gradle.kts diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java similarity index 100% rename from instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java similarity index 95% rename from instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java index db18fcf01b50..2c976dd626ba 100644 --- a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java +++ b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java @@ -113,7 +113,7 @@ AttributeInfo getAttributeInfo(MBeanServer server, ObjectName objectName) { // Verify correctness of configuration by attempting to extract the metric value. // The value will be discarded, but its type will be checked. - Object sampleValue = extractAttributeValue(server, objectName); + Object sampleValue = extractAttributeValue(server, objectName, logger); // Only numbers can be used to generate metric values if (sampleValue instanceof Number) { @@ -162,7 +162,10 @@ AttributeInfo getAttributeInfo(MBeanServer server, ObjectName objectName) { * * @param server the MBeanServer to use * @param objectName the ObjectName specifying the MBean to use, it should not be a pattern - * @param logger the logger to use, may be null + * @param logger the logger to use, may be null. Typically we want to log any issues with the + * attributes during MBean discovery, but once the attribute is successfuly detected and + * confirmed to be eligble for metric evaluation, any further attribute extraction + * malfunctions will be silent to avoid flooding the log. * @return the attribute value, if found, or null if an error occurred */ private Object extractAttributeValue(MBeanServer server, ObjectName objectName, Logger logger) { diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java similarity index 100% rename from instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java similarity index 100% rename from instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/DetectionStatus.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/DetectionStatus.java similarity index 100% rename from instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/DetectionStatus.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/DetectionStatus.java diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java similarity index 100% rename from instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java similarity index 100% rename from instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java similarity index 100% rename from instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricConfiguration.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricConfiguration.java similarity index 100% rename from instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricConfiguration.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricConfiguration.java diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java similarity index 100% rename from instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java similarity index 100% rename from instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java similarity index 100% rename from instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java diff --git a/instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java similarity index 100% rename from instrumentation/jmx/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java diff --git a/instrumentation/jmx/jmx-engine/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java b/instrumentation/jmx-metrics/jmx-engine/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java similarity index 100% rename from instrumentation/jmx/jmx-engine/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java rename to instrumentation/jmx-metrics/jmx-engine/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java diff --git a/instrumentation/jmx/jmx-yaml/library/build.gradle.kts b/instrumentation/jmx-metrics/jmx-yaml/library/build.gradle.kts similarity index 66% rename from instrumentation/jmx/jmx-yaml/library/build.gradle.kts rename to instrumentation/jmx-metrics/jmx-yaml/library/build.gradle.kts index 7dd35d0e9e8c..69042741983b 100644 --- a/instrumentation/jmx/jmx-yaml/library/build.gradle.kts +++ b/instrumentation/jmx-metrics/jmx-yaml/library/build.gradle.kts @@ -4,7 +4,7 @@ plugins { dependencies { implementation("org.yaml:snakeyaml") - implementation(project(":instrumentation:jmx:jmx-engine:library")) + implementation(project(":instrumentation:jmx-metrics:jmx-engine:library")) testImplementation(project(":testing-common")) } diff --git a/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java b/instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java similarity index 100% rename from instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java rename to instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java diff --git a/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java b/instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java similarity index 100% rename from instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java rename to instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java diff --git a/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java b/instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java similarity index 100% rename from instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java rename to instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java diff --git a/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java b/instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java similarity index 97% rename from instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java rename to instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java index 4cc2a03b70f2..f6cc52513fe3 100644 --- a/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java +++ b/instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java @@ -107,7 +107,7 @@ private static void addLabels(List list, Map tagMap private static MetricLabel buildLabel(String key, String target) { // The recognized forms of target are: // - param(STRING) - // - attrib(STRING) + // - attr(STRING) // - STRING // where STRING is the name of the corresponding parameter key, attribute name, // or the direct value to use @@ -118,9 +118,9 @@ private static MetricLabel buildLabel(String key, String target) { if (k > 0) { return new MetricLabel(key, MetricLabel.fromParameter(target.substring(6, k).trim())); } - } else if (target.startsWith("attrib(")) { + } else if (target.startsWith("attr(")) { if (k > 0) { - return new MetricLabel(key, MetricLabel.fromAttribute(target.substring(7, k).trim())); + return new MetricLabel(key, MetricLabel.fromAttribute(target.substring(5, k).trim())); } } else if (k < 0) { return new MetricLabel(key, MetricLabel.fromConstant(target)); diff --git a/instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java b/instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java similarity index 100% rename from instrumentation/jmx/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java rename to instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java diff --git a/instrumentation/jmx/jmx-yaml/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java b/instrumentation/jmx-metrics/jmx-yaml/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java similarity index 98% rename from instrumentation/jmx/jmx-yaml/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java rename to instrumentation/jmx-metrics/jmx-yaml/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java index d8bdc2dd1393..b67025d8f0bf 100644 --- a/instrumentation/jmx/jmx-yaml/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java +++ b/instrumentation/jmx-metrics/jmx-yaml/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java @@ -44,7 +44,7 @@ static void setup() throws Exception { + " - OBJECT:NAME2=*\n" + " label:\n" + " LABEL_KEY1: param(PARAMETER)\n" - + " LABEL_KEY2: attrib(ATTRIBUTE)\n" + + " LABEL_KEY2: attr(ATTRIBUTE)\n" + " prefix: METRIC_NAME_PREFIX\n" + " mapping:\n" + " ATTRIBUTE1:\n" @@ -133,7 +133,7 @@ void testConf3() throws Exception { + " - bean: my-test:type=4\n" + " label:\n" + " LABEL_KEY1: param(PARAMETER)\n" - + " LABEL_KEY2: attrib(ATTRIBUTE)\n" + + " LABEL_KEY2: attr(ATTRIBUTE)\n" + " prefix: PREFIX.\n" + " type: upDownCounter\n" + " unit: DEFAULT_UNIT\n" @@ -363,7 +363,7 @@ void testInvalidTag() throws Exception { + " mapping:\n" + " ATTRIB:\n" + " label:\n" - + " LABEL: attr(something)\n" + + " LABEL: attrib(something)\n" + " metric: METRIC_NAME\n"; runNegativeTest(yaml); } @@ -390,7 +390,7 @@ void testInvalidTagFromAttribute() throws Exception { + " mapping:\n" + " ATTRIB:\n" + " label:\n" - + " LABEL: attrib(.used)\n" + + " LABEL: attr(.used)\n" + " metric: METRIC_NAME\n"; runNegativeTest(yaml); } @@ -404,7 +404,7 @@ void testEmptyTagFromAttribute() throws Exception { + " mapping:\n" + " ATTRIB:\n" + " label:\n" - + " LABEL: attrib( )\n" + + " LABEL: attr( )\n" + " metric: METRIC_NAME\n"; runNegativeTest(yaml); } diff --git a/instrumentation/jmx/javaagent/build.gradle.kts b/instrumentation/jmx/javaagent/build.gradle.kts deleted file mode 100644 index 0804b9a57cfe..000000000000 --- a/instrumentation/jmx/javaagent/build.gradle.kts +++ /dev/null @@ -1,10 +0,0 @@ -plugins { - id("otel.javaagent-instrumentation") -} - -dependencies { - implementation(project(":instrumentation:jmx:jmx-engine:library")) - implementation(project(":instrumentation:jmx:jmx-yaml:library")) - - compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 39df775d853e..ae3814065052 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -298,9 +298,9 @@ include(":instrumentation:jetty-httpclient:jetty-httpclient-9.2:library") include(":instrumentation:jetty-httpclient:jetty-httpclient-9.2:testing") include(":instrumentation:jms-1.1:javaagent") include(":instrumentation:jms-1.1:javaagent-unit-tests") -include(":instrumentation:jmx:javaagent") -include(":instrumentation:jmx:jmx-engine:library") -include(":instrumentation:jmx:jmx-yaml:library") +include(":instrumentation:jmx-metrics:javaagent") +include(":instrumentation:jmx-metrics:jmx-engine:library") +include(":instrumentation:jmx-metrics:jmx-yaml:library") include(":instrumentation:jsf:jsf-common:javaagent") include(":instrumentation:jsf:jsf-common:testing") include(":instrumentation:jsf:jsf-mojarra-1.2:javaagent") From 5c0783debfec52eafcd9b572ab7843ac5eb95eb9 Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Wed, 5 Oct 2022 15:11:05 -0700 Subject: [PATCH 09/20] Correcting a typo --- .../instrumentation/jmx/engine/AttributeValueExtractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java index 2c976dd626ba..8bbf9318f393 100644 --- a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java +++ b/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java @@ -163,7 +163,7 @@ AttributeInfo getAttributeInfo(MBeanServer server, ObjectName objectName) { * @param server the MBeanServer to use * @param objectName the ObjectName specifying the MBean to use, it should not be a pattern * @param logger the logger to use, may be null. Typically we want to log any issues with the - * attributes during MBean discovery, but once the attribute is successfuly detected and + * attributes during MBean discovery, but once the attribute is successfully detected and * confirmed to be eligble for metric evaluation, any further attribute extraction * malfunctions will be silent to avoid flooding the log. * @return the attribute value, if found, or null if an error occurred From 7f89168c829904fc2206ddef157ca4d18ffa2997 Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Thu, 6 Oct 2022 11:15:57 -0700 Subject: [PATCH 10/20] Merging libraries jmx-engine and jmx-yaml into one. --- instrumentation/jmx-metrics/javaagent/build.gradle.kts | 3 +-- .../jmx-metrics/{jmx-engine => }/library/build.gradle.kts | 1 + .../instrumentation/jmx/engine/AttributeInfo.java | 0 .../instrumentation/jmx/engine/AttributeValueExtractor.java | 0 .../opentelemetry/instrumentation/jmx/engine/BeanFinder.java | 0 .../io/opentelemetry/instrumentation/jmx/engine/BeanPack.java | 0 .../instrumentation/jmx/engine/DetectionStatus.java | 0 .../instrumentation/jmx/engine/JmxMetricInsight.java | 0 .../instrumentation/jmx/engine/LabelExtractor.java | 0 .../opentelemetry/instrumentation/jmx/engine/MetricBanner.java | 0 .../instrumentation/jmx/engine/MetricConfiguration.java | 0 .../io/opentelemetry/instrumentation/jmx/engine/MetricDef.java | 0 .../instrumentation/jmx/engine/MetricExtractor.java | 0 .../opentelemetry/instrumentation/jmx/engine/MetricLabel.java | 0 .../instrumentation/jmx/engine/MetricRegistrar.java | 0 .../io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java | 0 .../io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java | 0 .../java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java | 0 .../instrumentation/jmx/yaml/MetricStructure.java | 0 .../io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java | 0 .../instrumentation/jmx/engine/AttributeExtractorTest.java | 0 .../instrumentation/jmx/engine/RuleParserTest.java | 0 settings.gradle.kts | 3 +-- 23 files changed, 3 insertions(+), 4 deletions(-) rename instrumentation/jmx-metrics/{jmx-engine => }/library/build.gradle.kts (75%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java (100%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java (100%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java (100%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java (100%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/DetectionStatus.java (100%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java (100%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java (100%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java (100%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricConfiguration.java (100%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java (100%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java (100%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java (100%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java (100%) rename instrumentation/jmx-metrics/{jmx-yaml => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java (100%) rename instrumentation/jmx-metrics/{jmx-yaml => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java (100%) rename instrumentation/jmx-metrics/{jmx-yaml => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java (100%) rename instrumentation/jmx-metrics/{jmx-yaml => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java (100%) rename instrumentation/jmx-metrics/{jmx-yaml => }/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java (100%) rename instrumentation/jmx-metrics/{jmx-engine => }/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java (100%) rename instrumentation/jmx-metrics/{jmx-yaml => }/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java (100%) diff --git a/instrumentation/jmx-metrics/javaagent/build.gradle.kts b/instrumentation/jmx-metrics/javaagent/build.gradle.kts index 84d770745ffe..e9b22ef2bcc3 100644 --- a/instrumentation/jmx-metrics/javaagent/build.gradle.kts +++ b/instrumentation/jmx-metrics/javaagent/build.gradle.kts @@ -3,8 +3,7 @@ plugins { } dependencies { - implementation(project(":instrumentation:jmx-metrics:jmx-engine:library")) - implementation(project(":instrumentation:jmx-metrics:jmx-yaml:library")) + implementation(project(":instrumentation:jmx-metrics:library")) compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") } diff --git a/instrumentation/jmx-metrics/jmx-engine/library/build.gradle.kts b/instrumentation/jmx-metrics/library/build.gradle.kts similarity index 75% rename from instrumentation/jmx-metrics/jmx-engine/library/build.gradle.kts rename to instrumentation/jmx-metrics/library/build.gradle.kts index e04e9398ca24..722db6cf773e 100644 --- a/instrumentation/jmx-metrics/jmx-engine/library/build.gradle.kts +++ b/instrumentation/jmx-metrics/library/build.gradle.kts @@ -3,6 +3,7 @@ plugins { } dependencies { + implementation("org.yaml:snakeyaml") testImplementation(project(":testing-common")) } diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/DetectionStatus.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/DetectionStatus.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/DetectionStatus.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/DetectionStatus.java diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricConfiguration.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricConfiguration.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricConfiguration.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricConfiguration.java diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java diff --git a/instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java diff --git a/instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java diff --git a/instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java diff --git a/instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java diff --git a/instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-yaml/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java diff --git a/instrumentation/jmx-metrics/jmx-engine/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-engine/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java rename to instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java diff --git a/instrumentation/jmx-metrics/jmx-yaml/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java similarity index 100% rename from instrumentation/jmx-metrics/jmx-yaml/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java rename to instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java diff --git a/settings.gradle.kts b/settings.gradle.kts index ae3814065052..96ecd330bc0e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -299,8 +299,7 @@ include(":instrumentation:jetty-httpclient:jetty-httpclient-9.2:testing") include(":instrumentation:jms-1.1:javaagent") include(":instrumentation:jms-1.1:javaagent-unit-tests") include(":instrumentation:jmx-metrics:javaagent") -include(":instrumentation:jmx-metrics:jmx-engine:library") -include(":instrumentation:jmx-metrics:jmx-yaml:library") +include(":instrumentation:jmx-metrics:library") include(":instrumentation:jsf:jsf-common:javaagent") include(":instrumentation:jsf:jsf-common:testing") include(":instrumentation:jsf:jsf-mojarra-1.2:javaagent") From 7e151ae2d0bae59e6b07dcba33988cc9302b6b34 Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Thu, 6 Oct 2022 15:21:12 -0700 Subject: [PATCH 11/20] Cleanup - removing leftover file. --- .../jmx-metrics/jmx-yaml/library/build.gradle.kts | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 instrumentation/jmx-metrics/jmx-yaml/library/build.gradle.kts diff --git a/instrumentation/jmx-metrics/jmx-yaml/library/build.gradle.kts b/instrumentation/jmx-metrics/jmx-yaml/library/build.gradle.kts deleted file mode 100644 index 69042741983b..000000000000 --- a/instrumentation/jmx-metrics/jmx-yaml/library/build.gradle.kts +++ /dev/null @@ -1,10 +0,0 @@ -plugins { - id("otel.library-instrumentation") -} - -dependencies { - implementation("org.yaml:snakeyaml") - implementation(project(":instrumentation:jmx-metrics:jmx-engine:library")) - - testImplementation(project(":testing-common")) -} From 46198c234bf4e0bbd17b3c73eacab0bfd900a8ad Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Fri, 7 Oct 2022 09:50:43 -0700 Subject: [PATCH 12/20] Making changes to the accepted YAML syntax: replacing 'label' with 'attribute'. Just within the README file. --- .../jmx-metrics/javaagent/README.md | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/instrumentation/jmx-metrics/javaagent/README.md b/instrumentation/jmx-metrics/javaagent/README.md index 75f8788e79ef..70818d2fd579 100644 --- a/instrumentation/jmx-metrics/javaagent/README.md +++ b/instrumentation/jmx-metrics/javaagent/README.md @@ -94,9 +94,9 @@ A more advanced example shows how to report similar metrics related to individua --- rules: - bean: java.lang:name=*,type=MemoryPool - label: + attribute: pool: param(name) - type: attr(Type) + type: beanattr(Type) mapping: Usage.used: metric: my.own.jvm.memory.pool.used @@ -110,7 +110,7 @@ rules: unit: By ``` -The ObjectName pattern will match a number of MBeans, each for a different memory pool. The number and names of available memory pools, however, will be known only at runtime. To report values for all actual memory pools using only two metrics, we use metric attributes (referenced by the configuration file as `label` elements). The first metric attribute, named `pool` will have its value derived from the ObjectName parameter `name` - which corresponds to the memory pool name. The second metric attribute, named `type` will get its value from the corresponding MBean attribute named `Type`. The values of this attribute are strings `HEAP` or `NON_HEAP` classifying the corresponding memory pool. Here the definition of the metric attributes is shared by both metrics, but it is also possible to define them at the individual metric level. +The ObjectName pattern will match a number of MBeans, each for a different memory pool. The number and names of available memory pools, however, will be known only at runtime. To report values for all actual memory pools using only two metrics, we use metric attributes (referenced by the configuration file as `attribute` elements). The first metric attribute, named `pool` will have its value derived from the ObjectName parameter `name` - which corresponds to the memory pool name. The second metric attribute, named `type` will get its value from the corresponding MBean attribute named `Type`. The values of this attribute are strings `HEAP` or `NON_HEAP` classifying the corresponding memory pool. Here the definition of the metric attributes is shared by both metrics, but it is also possible to define them at the individual metric level. Using the above rule, when running on HotSpot JVM for Java 11, the following combinations of metric attributes will be reported. - {pool="Compressed Class Space", type="NON_HEAP"} @@ -132,19 +132,19 @@ Sometimes it is desired to merge several MBean attributes into a single metric, --- rules: - bean: Catalina:type=GlobalRequestProcessor,name=* - label: + attribute: handler: param(name) type: counter mapping: bytesReceived: metric: catalina.traffic - label: + attribute: direction: in desc: The number of transmitted bytes unit: By bytesSent: metric: catalina.traffic - label: + attribute: direction: out desc: The number of transmitted bytes unit: By @@ -164,7 +164,7 @@ While it is possible to define MBeans based metrics with fine details, sometimes --- rules: - bean: kafka.streams:type=stream-thread-metrics,thread-id=* - label: + attribute: threadId: param(thread-id) prefix: my.kafka.streams. unit: ms @@ -182,7 +182,7 @@ rules: poll-records-max: unit: 1 - bean: kafka.streams:type=stream-thread-metrics,thread-id=* - label: + attribute: threadId: param(thread-id) prefix: my.kafka.streams. unit: /s @@ -194,7 +194,7 @@ rules: task-closed-rate: skipped-records-rate: - bean: kafka.streams:type=stream-thread-metrics,thread-id=* - label: + attribute: threadId: param(thread-id) prefix: my.kafka.streams.totals. unit: 1 @@ -207,7 +207,7 @@ rules: task-closed-total: ``` Because we declared metric prefix (here `my.kafka.streams.`) and did not specify actual metric names, the metric names will be generated automatically, by appending the corresponding MBean attribute name to the prefix. -Thus, the above definitions will create several metrics, named `my.kafka.streams.commit-latency-avg`, `my.kafka.streams.commit-latency-max`, and so on. For the first configuration rule, the default unit has been changed to `ms`, which remains in effect for all attribute mappings listed within the rule, unless they define their own unit. Similarly, the second configuration rule defines the unit as `/s`, valid for all the rates reported. +Thus, the above definitions will create several metrics, named `my.kafka.streams.commit-latency-avg`, `my.kafka.streams.commit-latency-max`, and so on. For the first configuration rule, the default unit has been changed to `ms`, which remains in effect for all MBean attribute mappings listed within the rule, unless they define their own unit. Similarly, the second configuration rule defines the unit as `/s`, valid for all the rates reported. The metric descriptions will remain undefined, unless they are provided by the queried MBeans. @@ -217,51 +217,51 @@ Here is the general description of the accepted configuration file syntax. The w ```yaml --- -rules: # start of list of configuration rules - - bean: # can contain wildcards - label: # optional metric attributes, they apply to all metrics below - : param() # is used as the key to extract value from actual ObjectName - : attr() # is used as the attribute name to extract value from MBean - prefix: # optional, useful for avoiding specifying metric names below - unit: # optional, redefines the default unit for the whole rule - type: # optional, redefines the default type for the whole rule +rules: # start of list of configuration rules + - bean: # can contain wildcards + attribute: # optional metric attributes, they apply to all metrics below + : param() # is used as the key to extract value from actual ObjectName + : beanattr() # is used as the MBean attribute name to extract the value + prefix: # optional, useful for avoiding specifying metric names below + unit: # optional, redefines the default unit for the whole rule + type: # optional, redefines the default type for the whole rule mapping: - : # an MBean attribute name defining the metric value - metric: # metric name will be - type: # optional, the default type is gauge - desc: # optional - unit: # optional - label: # optional, will be used in addition to the shared labels above - : # direct value for the label - : # use a.b to get access into CompositeData - metric: # optional, the default is the MBean attribute name - unit: # optional - : # metric name will be - : # metric name will be - - beans: # alternatively, if multiple object names are needed - - # at least one object name must be specified + : # an MBean attribute name defining the metric value + metric: # metric name will be + type: # optional, the default type is gauge + desc: # optional + unit: # optional + attribute: # optional, will be used in addition to the shared metric attributes above + : # direct value for the metric attribute + : # use a.b to get access into CompositeData + metric: # optional, the default is the MBean attribute name + unit: # optional + : # metric name will be + : # metric name will be + - beans: # alternatively, if multiple object names are needed + - # at least one object name must be specified - mapping: - : # an MBean attribute name defining the metric value - metric: # metric name will be - type: updowncounter # optional - : # metric name will be + : # an MBean attribute name defining the metric value + metric: # metric name will be + type: updowncounter # optional + : # metric name will be ``` The following table explains the used terms with more details. | Syntactic Element | Description | | ---------------- | --------------- | | OBJECTNAME | A syntactically valid string representing an ObjectName (see [ObjectName constructor](https://docs.oracle.com/javase/8/docs/api/javax/management/ObjectName.html#ObjectName-java.lang.String-)). | -| LABEL | Any well-formed string that can be used as a metric [attribute](https://opentelemetry.io/docs/reference/specification/common/#attribute) key. | -| ATTR | A non-empty string used as a name of the MBean attribute. The attribute value must be a String, otherwise the specified label (metric attribute) will not be used. | -| PARAM | A non-empty string used as a property key for the ObjectName identifying the MBean which provides the metric value. If the ObjectName does not have a property with the given key, the specified label will not be used. | +| ATTRIBUTE | Any well-formed string that can be used as a metric [attribute](https://opentelemetry.io/docs/reference/specification/common/#attribute) key. | +| ATTR | A non-empty string used as a name of the MBean attribute. The MBean attribute value must be a String, otherwise the specified metric attribute will not be used. | +| PARAM | A non-empty string used as a property key for the ObjectName identifying the MBean which provides the metric value. If the ObjectName does not have a property with the given key, the specified metric attribute will not be used. | | METRIC_NAME_PREFIX | Any non-empty string which will be prepended to the specified metric (instrument) names. | | METRIC_NAME | Any non-empty string. The string, prefixed by the optional prefix (see above) must satisfy [instrument naming rule](https://opentelemetry.io/docs/reference/specification/metrics/api/#instrument-naming-rule). | | TYPE | One of `counter`, `updowncounter`, or `gauge`. The default is `gauge`. This value is case insensitive. | | DESCRIPTION | Any string to be used as human-readable [description](https://opentelemetry.io/docs/reference/specification/metrics/api/#instrument-description) of the metric. If the description is not provided by the rule, an attempt will be made to extract one automatically from the corresponding MBean. | | UNIT | A string identifying the [unit](https://opentelemetry.io/docs/reference/specification/metrics/api/#instrument-unit) of measurements reported by the metric. Enclose the string in single or double quotes if using unit annotations. | -| STRING | Any string to be used directly as the label value. | -| ATTRIBUTE | A non-empty string representing the MBean attribute defining the metric value. The attribute value must be a number. Special dot-notation _attributeName.itemName_ can be used to access numerical items within attributes of [CompositeType](https://docs.oracle.com/javase/8/docs/api/javax/management/openmbean/CompositeType.html). | +| STRING | Any string to be used directly as the metric attribute value. | +| BEANATTR | A non-empty string representing the MBean attribute defining the metric value. The attribute value must be a number. Special dot-notation _attributeName.itemName_ can be used to access numerical items within attributes of [CompositeType](https://docs.oracle.com/javase/8/docs/api/javax/management/openmbean/CompositeType.html). | ## Assumptions and Limitations From 112a04d1f95a4ad706c0183ce27644ef40174388 Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Fri, 28 Oct 2022 10:26:04 -0700 Subject: [PATCH 13/20] Using "metricAttribute" in place of "label" or "attribute", "beanattr()" instead of "attr()", and "const(STRING)" instead of "STRING". --- .../jmx-metrics/javaagent/README.md | 34 +++---- .../main/resources/jmx/rules/activemq.yaml | 6 +- .../src/main/resources/jmx/rules/hadoop.yaml | 14 +-- .../src/main/resources/jmx/rules/jetty.yaml | 4 +- .../resources/jmx/rules/kafka-broker.yaml | 36 ++++---- .../src/main/resources/jmx/rules/tomcat.yaml | 22 ++--- .../src/main/resources/jmx/rules/wildfly.yaml | 36 ++++---- ...actor.java => BeanAttributeExtractor.java} | 16 ++-- .../jmx/engine/MetricAttribute.java | 51 +++++++++++ ...tor.java => MetricAttributeExtractor.java} | 6 +- .../instrumentation/jmx/engine/MetricDef.java | 13 +-- .../jmx/engine/MetricExtractor.java | 17 ++-- .../jmx/engine/MetricLabel.java | 51 ----------- .../jmx/engine/MetricRegistrar.java | 22 ++--- .../instrumentation/jmx/yaml/JmxRule.java | 60 +++++++------ .../jmx/yaml/MetricStructure.java | 77 +++++++++------- .../jmx/engine/AttributeExtractorTest.java | 26 +++--- .../jmx/engine/RuleParserTest.java | 89 ++++++++++--------- 18 files changed, 298 insertions(+), 282 deletions(-) rename instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/{AttributeValueExtractor.java => BeanAttributeExtractor.java} (93%) create mode 100644 instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttribute.java rename instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/{LabelExtractor.java => MetricAttributeExtractor.java} (62%) delete mode 100644 instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java diff --git a/instrumentation/jmx-metrics/javaagent/README.md b/instrumentation/jmx-metrics/javaagent/README.md index 70818d2fd579..c2eef2a60c8b 100644 --- a/instrumentation/jmx-metrics/javaagent/README.md +++ b/instrumentation/jmx-metrics/javaagent/README.md @@ -94,7 +94,7 @@ A more advanced example shows how to report similar metrics related to individua --- rules: - bean: java.lang:name=*,type=MemoryPool - attribute: + metricAttribute: pool: param(name) type: beanattr(Type) mapping: @@ -110,7 +110,7 @@ rules: unit: By ``` -The ObjectName pattern will match a number of MBeans, each for a different memory pool. The number and names of available memory pools, however, will be known only at runtime. To report values for all actual memory pools using only two metrics, we use metric attributes (referenced by the configuration file as `attribute` elements). The first metric attribute, named `pool` will have its value derived from the ObjectName parameter `name` - which corresponds to the memory pool name. The second metric attribute, named `type` will get its value from the corresponding MBean attribute named `Type`. The values of this attribute are strings `HEAP` or `NON_HEAP` classifying the corresponding memory pool. Here the definition of the metric attributes is shared by both metrics, but it is also possible to define them at the individual metric level. +The ObjectName pattern will match a number of MBeans, each for a different memory pool. The number and names of available memory pools, however, will be known only at runtime. To report values for all actual memory pools using only two metrics, we use metric attributes (referenced by the configuration file as `metricAttribute` elements). The first metric attribute, named `pool` will have its value derived from the ObjectName parameter `name` - which corresponds to the memory pool name. The second metric attribute, named `type` will get its value from the corresponding MBean attribute named `Type`. The values of this attribute are strings `HEAP` or `NON_HEAP` classifying the corresponding memory pool. Here the definition of the metric attributes is shared by both metrics, but it is also possible to define them at the individual metric level. Using the above rule, when running on HotSpot JVM for Java 11, the following combinations of metric attributes will be reported. - {pool="Compressed Class Space", type="NON_HEAP"} @@ -132,29 +132,29 @@ Sometimes it is desired to merge several MBean attributes into a single metric, --- rules: - bean: Catalina:type=GlobalRequestProcessor,name=* - attribute: + metricAttribute: handler: param(name) type: counter mapping: bytesReceived: metric: catalina.traffic - attribute: - direction: in + metricAttribute: + direction: const(in) desc: The number of transmitted bytes unit: By bytesSent: metric: catalina.traffic - attribute: - direction: out + metricAttribute: + direction: const(out) desc: The number of transmitted bytes unit: By ``` -The referenced MBean has two attributes of interest, `bytesReceived`, and `bytesSent`. We want them to be reported by just one metric, but keeping the values separate by using metric attribute `direction`. This is achieved by specifying the same metric name `catalina.traffic` when mapping the MBean attributes to metrics. There will be two metric attributes provided: `handler`, which has a shared definition, and `direction`, which has its value (`in` or `out`) declared directly, depending on the MBean attribute providing the metric value. +The referenced MBean has two attributes of interest, `bytesReceived`, and `bytesSent`. We want them to be reported by just one metric, but keeping the values separate by using metric attribute `direction`. This is achieved by specifying the same metric name `catalina.traffic` when mapping the MBean attributes to metrics. There will be two metric attributes provided: `handler`, which has a shared definition, and `direction`, which has its value (`in` or `out`) declared directly as constants, depending on the MBean attribute providing the metric value. Keep in mind that when defining a metric multiple times like this, its type, unit and description must be exactly the same. Otherwise there will be complaints about attempts to redefine a metric in a non-compatible way. The example also demonstrates that when specifying a number of MBean attribute mappings within the same rule, the metric type can be declared only once (outside of the `mapping` section). -Even when not reusing the metric name, special care also has to be taken when using ObjectName patterns (or specifying multiple ObjectNames - see the General Syntax section at the bottom of the page). Different ObjectNames matching the pattern must result in using different metric attributes. Otherwise the same metric will be reported multiple times (using different values), which will likely clobber the previous values. +Even when not reusing the metric name, special care also has to be taken when using ObjectName patterns (or specifying multiple ObjectNames - see the General Syntax section at the bottom of the page). Different ObjectNames matching the pattern must result in using different metric attribute values. Otherwise the same metric will be reported multiple times (using different metric values), which will likely clobber the previous values. ### Making shortcuts @@ -164,7 +164,7 @@ While it is possible to define MBeans based metrics with fine details, sometimes --- rules: - bean: kafka.streams:type=stream-thread-metrics,thread-id=* - attribute: + metricAttribute: threadId: param(thread-id) prefix: my.kafka.streams. unit: ms @@ -182,7 +182,7 @@ rules: poll-records-max: unit: 1 - bean: kafka.streams:type=stream-thread-metrics,thread-id=* - attribute: + metricAttribute: threadId: param(thread-id) prefix: my.kafka.streams. unit: /s @@ -194,7 +194,7 @@ rules: task-closed-rate: skipped-records-rate: - bean: kafka.streams:type=stream-thread-metrics,thread-id=* - attribute: + metricAttribute: threadId: param(thread-id) prefix: my.kafka.streams.totals. unit: 1 @@ -219,7 +219,7 @@ Here is the general description of the accepted configuration file syntax. The w --- rules: # start of list of configuration rules - bean: # can contain wildcards - attribute: # optional metric attributes, they apply to all metrics below + metricAttribute: # optional metric attributes, they apply to all metrics below : param() # is used as the key to extract value from actual ObjectName : beanattr() # is used as the MBean attribute name to extract the value prefix: # optional, useful for avoiding specifying metric names below @@ -231,8 +231,8 @@ rules: # start of list of configuration rules type: # optional, the default type is gauge desc: # optional unit: # optional - attribute: # optional, will be used in addition to the shared metric attributes above - : # direct value for the metric attribute + metricAttribute: # optional, will be used in addition to the shared metric attributes above + : const() # direct value for the metric attribute : # use a.b to get access into CompositeData metric: # optional, the default is the MBean attribute name unit: # optional @@ -254,13 +254,13 @@ The following table explains the used terms with more details. | OBJECTNAME | A syntactically valid string representing an ObjectName (see [ObjectName constructor](https://docs.oracle.com/javase/8/docs/api/javax/management/ObjectName.html#ObjectName-java.lang.String-)). | | ATTRIBUTE | Any well-formed string that can be used as a metric [attribute](https://opentelemetry.io/docs/reference/specification/common/#attribute) key. | | ATTR | A non-empty string used as a name of the MBean attribute. The MBean attribute value must be a String, otherwise the specified metric attribute will not be used. | -| PARAM | A non-empty string used as a property key for the ObjectName identifying the MBean which provides the metric value. If the ObjectName does not have a property with the given key, the specified metric attribute will not be used. | +| PARAM | A non-empty string used as a property key in the ObjectName identifying the MBean which provides the metric value. If the ObjectName does not have a property with the given key, the specified metric attribute will not be used. | | METRIC_NAME_PREFIX | Any non-empty string which will be prepended to the specified metric (instrument) names. | | METRIC_NAME | Any non-empty string. The string, prefixed by the optional prefix (see above) must satisfy [instrument naming rule](https://opentelemetry.io/docs/reference/specification/metrics/api/#instrument-naming-rule). | | TYPE | One of `counter`, `updowncounter`, or `gauge`. The default is `gauge`. This value is case insensitive. | | DESCRIPTION | Any string to be used as human-readable [description](https://opentelemetry.io/docs/reference/specification/metrics/api/#instrument-description) of the metric. If the description is not provided by the rule, an attempt will be made to extract one automatically from the corresponding MBean. | | UNIT | A string identifying the [unit](https://opentelemetry.io/docs/reference/specification/metrics/api/#instrument-unit) of measurements reported by the metric. Enclose the string in single or double quotes if using unit annotations. | -| STRING | Any string to be used directly as the metric attribute value. | +| STR | Any string to be used directly as the metric attribute value. | | BEANATTR | A non-empty string representing the MBean attribute defining the metric value. The attribute value must be a number. Special dot-notation _attributeName.itemName_ can be used to access numerical items within attributes of [CompositeType](https://docs.oracle.com/javase/8/docs/api/javax/management/openmbean/CompositeType.html). | ## Assumptions and Limitations diff --git a/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/activemq.yaml b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/activemq.yaml index 16711fd3a13d..3b4e03334fa5 100644 --- a/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/activemq.yaml +++ b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/activemq.yaml @@ -4,7 +4,7 @@ rules: - beans: - org.apache.activemq:type=Broker,brokerName=*,destinationType=Queue,destinationName=* - org.apache.activemq:type=Broker,brokerName=*,destinationType=Topic,destinationName=* - label: + metricAttribute: destination: param(destinationName) broker: param(brokerName) prefix: activemq. @@ -49,6 +49,8 @@ rules: desc: The average time a message was held on this destination - bean: org.apache.activemq:type=Broker,brokerName=* + metricAttribute: + broker: param(brokerName) prefix: activemq. unit: '%' type: gauge @@ -63,4 +65,4 @@ rules: desc: The percentage of configured disk used for persistent messages TempPercentUsage: metric: disc.TempPercentUsage - desc: The percentage of configured disk used for non-persistent messages \ No newline at end of file + desc: The percentage of configured disk used for non-persistent messages diff --git a/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/hadoop.yaml b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/hadoop.yaml index ae35a40a3ed0..f89de461230c 100644 --- a/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/hadoop.yaml +++ b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/hadoop.yaml @@ -3,7 +3,7 @@ rules: - bean: Hadoop:service=NameNode,name=FSNamesystem unit: 1 prefix: hadoop. - label: + metricAttribute: node_name: param(tag.Hostname) mapping: CapacityUsed: @@ -35,8 +35,8 @@ rules: type: updowncounter unit: '{volumes}' desc: Total number of volume failures across all data nodes - label: - direction: sent + metricAttribute: + direction: const(sent) FilesTotal: metric: file.FilesTotal type: updowncounter @@ -52,12 +52,12 @@ rules: type: updowncounter unit: '{nodes}' desc: The Number of data nodes - label: - state: live + metricAttribute: + state: const(live) NumDeadDataNodes: metric: datenode.Count type: updowncounter unit: '{nodes}' desc: The Number of data nodes - label: - state: dead + metricAttribute: + state: const(dead) diff --git a/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/jetty.yaml b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/jetty.yaml index 610c37ea3f48..021e615cc069 100644 --- a/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/jetty.yaml +++ b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/jetty.yaml @@ -5,7 +5,7 @@ rules: unit: s prefix: jetty.session. type: updowncounter - label: + metricAttribute: resource: param(context) mapping: sessionsCreated: @@ -38,7 +38,7 @@ rules: - bean: org.eclipse.jetty.io:context=*,type=managedselector,id=* prefix: jetty.io. - label: + metricAttribute: resource: param(context) id: param(id) mapping: diff --git a/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/kafka-broker.yaml b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/kafka-broker.yaml index f85c58a999e1..251c83091b01 100644 --- a/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/kafka-broker.yaml +++ b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/kafka-broker.yaml @@ -11,8 +11,8 @@ rules: unit: '{messages}' - bean: kafka.server:type=BrokerTopicMetrics,name=TotalFetchRequestsPerSec - label: - type: fetch + metricAttribute: + type: const(fetch) mapping: Count: metric: kafka.request.count @@ -21,8 +21,8 @@ rules: unit: '{requests}' - bean: kafka.server:type=BrokerTopicMetrics,name=TotalProduceRequestsPerSec - label: - type: produce + metricAttribute: + type: const(produce) mapping: Count: metric: kafka.request.count @@ -31,8 +31,8 @@ rules: unit: '{requests}' - bean: kafka.server:type=BrokerTopicMetrics,name=FailedFetchRequestsPerSec - label: - type: fetch + metricAttribute: + type: const(fetch) mapping: Count: metric: kafka.request.failed @@ -41,8 +41,8 @@ rules: unit: '{requests}' - bean: kafka.server:type=BrokerTopicMetrics,name=FailedProduceRequestsPerSec - label: - type: produce + metricAttribute: + type: const(produce) mapping: Count: metric: kafka.request.failed @@ -54,7 +54,7 @@ rules: - kafka.network:type=RequestMetrics,name=TotalTimeMs,request=Produce - kafka.network:type=RequestMetrics,name=TotalTimeMs,request=FetchConsumer - kafka.network:type=RequestMetrics,name=TotalTimeMs,request=FetchFollower - label: + metricAttribute: type: param(request) unit: ms mapping: @@ -80,8 +80,8 @@ rules: unit: '{requests}' - bean: kafka.server:type=BrokerTopicMetrics,name=BytesInPerSec - label: - direction: in + metricAttribute: + direction: const(in) mapping: Count: metric: kafka.network.io @@ -90,8 +90,8 @@ rules: unit: By - bean: kafka.server:type=BrokerTopicMetrics,name=BytesOutPerSec - label: - direction: out + metricAttribute: + direction: const(out) mapping: Count: metric: kafka.network.io @@ -102,7 +102,7 @@ rules: - beans: - kafka.server:type=DelayedOperationPurgatory,name=PurgatorySize,delayedOperation=Produce - kafka.server:type=DelayedOperationPurgatory,name=PurgatorySize,delayedOperation=Fetch - label: + metricAttribute: type: param(delayedOperation) mapping: Value: @@ -136,8 +136,8 @@ rules: unit: '{partitions}' - bean: kafka.server:type=ReplicaManager,name=IsrShrinksPerSec - label: - operation: shrink + metricAttribute: + operation: const(shrink) mapping: Count: metric: kafka.isr.operation.count @@ -146,8 +146,8 @@ rules: unit: '{operations}' - bean: kafka.server:type=ReplicaManager,name=IsrExpandsPerSec - label: - operation: expand + metricAttribute: + operation: const(expand) mapping: Count: metric: kafka.isr.operation.count diff --git a/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/tomcat.yaml b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/tomcat.yaml index 309fc57163ec..e7041bcc34ac 100644 --- a/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/tomcat.yaml +++ b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/tomcat.yaml @@ -3,7 +3,7 @@ rules: - bean: Catalina:type=GlobalRequestProcessor,name=* unit: 1 prefix: http.server.tomcat. - label: + metricAttribute: name: param(name) mapping: errorCount: @@ -29,20 +29,20 @@ rules: type: counter unit: By desc: The number of bytes transmitted - label: - direction: received + metricAttribute: + direction: const(received) bytesSent: metric: traffic type: counter unit: By desc: The number of bytes transmitted - label: - direction: sent + metricAttribute: + direction: const(sent) - bean: Catalina:type=Manager,host=localhost,context=* unit: 1 prefix: http.server.tomcat. type: updowncounter - label: + metricAttribute: context: param(context) mapping: activeSessions: @@ -52,16 +52,16 @@ rules: unit: '{threads}' prefix: http.server.tomcat. type: updowncounter - label: + metricAttribute: name: param(name) mapping: currentThreadCount: metric: threads desc: Thread Count of the Thread Pool - label: - state: idle + metricAttribute: + state: const(idle) currentThreadsBusy: metric: threads desc: Thread Count of the Thread Pool - label: - state: busy \ No newline at end of file + metricAttribute: + state: const(busy) diff --git a/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/wildfly.yaml b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/wildfly.yaml index f350e5b98466..82aff5ee9a7f 100644 --- a/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/wildfly.yaml +++ b/instrumentation/jmx-metrics/javaagent/src/main/resources/jmx/rules/wildfly.yaml @@ -1,7 +1,7 @@ --- rules: - bean: jboss.as:deployment=*,subsystem=undertow - label: + metricAttribute: deployment: param(deployment) prefix: wildfly.session. type: counter @@ -13,7 +13,7 @@ rules: expiredSessions: rejectedSessions: - bean: jboss.as:subsystem=undertow,server=*,http-listener=* - label: + metricAttribute: server: param(server) listener: param(http-listener) prefix: wildfly.request. @@ -25,7 +25,7 @@ rules: unit: ns errorCount: - bean: jboss.as:subsystem=undertow,server=*,http-listener=* - label: + metricAttribute: server: param(server) listener: param(http-listener) type: counter @@ -34,27 +34,27 @@ rules: bytesSent: metric: wildfly.network.io desc: Total number of bytes transferred - label: - direction: out + metricAttribute: + direction: const(out) bytesReceived: metric: wildfly.network.io desc: Total number of bytes transferred - label: - direction: in + metricAttribute: + direction: const(in) - bean: jboss.as:subsystem=datasources,data-source=*,statistics=pool unit: 1 - label: + metricAttribute: data_source: param(data-source) mapping: ActiveCount: metric: wildfly.db.client.connections.usage - label: - state: used + metricAttribute: + state: const(used) desc: The number of open jdbc connections IdleCount: metric: wildfly.db.client.connections.usage - label: - state: idle + metricAttribute: + state: const(idle) desc: The number of open jdbc connections WaitCount: metric: wildfly.db.client.connections.WaitCount @@ -68,16 +68,16 @@ rules: metric: transaction.NumberOfTransactions numberOfApplicationRollbacks: metric: rollback.count - label: - cause: application + metricAttribute: + cause: const(application) desc: The total number of transactions rolled back numberOfResourceRollbacks: metric: rollback.count - label: - cause: resource + metricAttribute: + cause: const(resource) desc: The total number of transactions rolled back numberOfSystemRollbacks: metric: rollback.count - label: - cause: system + metricAttribute: + cause: const(system) desc: The total number of transactions rolled back diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanAttributeExtractor.java similarity index 93% rename from instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanAttributeExtractor.java index 8bbf9318f393..bfa9e3e01c91 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeValueExtractor.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanAttributeExtractor.java @@ -22,9 +22,9 @@ * A class responsible for extracting attribute values from MBeans. Objects of this class are * immutable. */ -public class AttributeValueExtractor implements LabelExtractor { +public class BeanAttributeExtractor implements MetricAttributeExtractor { - private static final Logger logger = Logger.getLogger(AttributeValueExtractor.class.getName()); + private static final Logger logger = Logger.getLogger(BeanAttributeExtractor.class.getName()); // The attribute name to be used during value extraction from MBean private final String baseName; @@ -37,10 +37,10 @@ public class AttributeValueExtractor implements LabelExtractor { * Verify the attribute name and create a corresponding extractor object. * * @param rawName the attribute name, can be a reference to composite values - * @return the corresponding LabelValueExtractor + * @return the corresponding BeanAttributeExtractor * @throws IllegalArgumentException if the attribute name is malformed */ - public static AttributeValueExtractor fromName(String rawName) { + public static BeanAttributeExtractor fromName(String rawName) { if (rawName.isEmpty()) { throw new IllegalArgumentException("Empty attribute name"); } @@ -48,7 +48,7 @@ public static AttributeValueExtractor fromName(String rawName) { // Check if a CompositeType value is expected int k = rawName.indexOf('.'); if (k < 0) { - return new AttributeValueExtractor(rawName); + return new BeanAttributeExtractor(rawName); } // Set up extraction from CompositeType values @@ -65,12 +65,12 @@ public static AttributeValueExtractor fromName(String rawName) { throw new IllegalArgumentException("Invalid attribute name '" + rawName + "'"); } } - return new AttributeValueExtractor(baseName, components); + return new BeanAttributeExtractor(baseName, components); } - public AttributeValueExtractor(String baseName, String... nameChain) { + public BeanAttributeExtractor(String baseName, String... nameChain) { if (baseName == null || nameChain == null) { - throw new IllegalArgumentException("null argument for AttributeValueExtractor"); + throw new IllegalArgumentException("null argument for BeanAttributeExtractor"); } this.baseName = baseName; this.nameChain = nameChain; diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttribute.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttribute.java new file mode 100644 index 000000000000..bdef32f65174 --- /dev/null +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttribute.java @@ -0,0 +1,51 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jmx.engine; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +/** + * A class representing a metric attribute. It is responsible for extracting the attribute value (to + * be reported as a Measurement attribute), and for holding the corresponding attribute name to be + * used. Objects of this class are immutable. + */ +public class MetricAttribute { + private final String name; + private final MetricAttributeExtractor extractor; + + public MetricAttribute(String name, MetricAttributeExtractor extractor) { + this.name = name; + this.extractor = extractor; + } + + public String getAttributeName() { + return name; + } + + String acquireAttributeValue(MBeanServer server, ObjectName objectName) { + return extractor.extractValue(server, objectName); + } + + public static MetricAttributeExtractor fromConstant(String constantValue) { + return (a, b) -> { + return constantValue; + }; + } + + public static MetricAttributeExtractor fromObjectNameParameter(String parameterKey) { + if (parameterKey.isEmpty()) { + throw new IllegalArgumentException("Empty parameter name"); + } + return (dummy, objectName) -> { + return objectName.getKeyProperty(parameterKey); + }; + } + + public static MetricAttributeExtractor fromBeanAttribute(String attributeName) { + return BeanAttributeExtractor.fromName(attributeName); + } +} diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttributeExtractor.java similarity index 62% rename from instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttributeExtractor.java index b31666853b48..4480a7e86837 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/LabelExtractor.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttributeExtractor.java @@ -9,10 +9,10 @@ import javax.management.ObjectName; /** - * LabelExtractors are responsible for obtaining values for populating Labels, i.e. Measurement - * attributes. + * MetricAttributeExtractors are responsible for obtaining values for populating metric attributes, + * i.e. measurement attributes. */ -public interface LabelExtractor { +public interface MetricAttributeExtractor { String extractValue(MBeanServer server, ObjectName objectName); } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java index 3d812a0bc513..8f40e9bb3e51 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java @@ -7,8 +7,8 @@ /** * A class providing a complete definition on how to create an Open Telemetry metric out of the JMX - * system: how to extract values from MBeans and how to model, name and label them using - * OpenTelemetry Metric API. Objects of this class are immutable. + * system: how to extract values from MBeans and how to model, name and decorate them with + * attributes using OpenTelemetry Metric API. Objects of this class are immutable. * *

    Example: The JVM provides an MBean with ObjectName "java.lang:type=Threading", and one of the * MBean attributes is "ThreadCount". This MBean can be used to provide a metric showing the current @@ -16,7 +16,7 @@ * *

    new MetricDef(new BeanPack(null, new ObjectName("java.lang:type=Threading")), * - *

    new MetricExtractor(new AttributeValueExtractor("ThreadCount"), + *

    new MetricExtractor(new BeanAttributeExtractor("ThreadCount"), * *

    new MetricBanner("process.runtime.jvm.threads", "Current number of threads", "1" ))); */ @@ -25,15 +25,16 @@ public class MetricDef { // Describes the MBeans to use private final BeanPack beans; - // Describes how to get the metric values and their labels (dimensions), and how to report them + // Describes how to get the metric values and their attributes, and how to report them private final MetricExtractor[] metricExtractors; /** * Constructor for MetricDef. * * @param beans description of MBeans required to obtain metric values - * @param metricExtractors description of how to extract and label metric values; if more than one - * MetricExtractor is provided, they should use unique metric names or unique labels + * @param metricExtractors description of how to extract metric values; if more than one + * MetricExtractor is provided, they should use unique metric names or unique metric + * attributes */ public MetricDef(BeanPack beans, MetricExtractor... metricExtractors) { this.beans = beans; diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java index 0b43df732b00..6d49081de9dd 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java @@ -17,31 +17,32 @@ public class MetricExtractor { private final MetricBanner banner; // Defines the way to access the metric value (a number) - private final AttributeValueExtractor attributeExtractor; + private final BeanAttributeExtractor attributeExtractor; // Defines the Measurement attributes to be used when reporting the metric value. - // We call them labels to avoid confusion with MBean attributes - private final MetricLabel[] labels; + private final MetricAttribute[] attributes; private volatile DetectionStatus status; public MetricExtractor( - AttributeValueExtractor attributeExtractor, MetricBanner banner, MetricLabel... labels) { + BeanAttributeExtractor attributeExtractor, + MetricBanner banner, + MetricAttribute... attributes) { this.attributeExtractor = attributeExtractor; this.banner = banner; - this.labels = labels; + this.attributes = attributes; } MetricBanner getBanner() { return banner; } - AttributeValueExtractor getMetricValueExtractor() { + BeanAttributeExtractor getMetricValueExtractor() { return attributeExtractor; } - MetricLabel[] getLabels() { - return labels; + MetricAttribute[] getAttributes() { + return attributes; } void setStatus(DetectionStatus status) { diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java deleted file mode 100644 index 27083ce104cc..000000000000 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricLabel.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.jmx.engine; - -import javax.management.MBeanServer; -import javax.management.ObjectName; - -/** - * A class representing a metric attribute (label). It is responsible for extracting a label value - * (to be reported as a Measurement attribute), and for holding the corresponding label name to be - * used. Objects of this class are immutable. - */ -public class MetricLabel { - private final String labelName; - private final LabelExtractor extractor; - - public MetricLabel(String labelName, LabelExtractor extractor) { - this.labelName = labelName; - this.extractor = extractor; - } - - public String getLabelName() { - return labelName; - } - - String extractLabelValue(MBeanServer server, ObjectName objectName) { - return extractor.extractValue(server, objectName); - } - - public static LabelExtractor fromConstant(String constantValue) { - return (a, b) -> { - return constantValue; - }; - } - - public static LabelExtractor fromParameter(String parameterKey) { - if (parameterKey.isEmpty()) { - throw new IllegalArgumentException("Empty parameter name"); - } - return (dummy, objectName) -> { - return objectName.getKeyProperty(parameterKey); - }; - } - - public static LabelExtractor fromAttribute(String attributeName) { - return AttributeValueExtractor.fromName(attributeName); - } -} diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java index d67e1256f1f1..49ac9f2676ed 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java @@ -144,8 +144,8 @@ static Consumer doubleTypeCallback(MetricExtractor Number metricValue = extractor.getMetricValueExtractor().extractNumericalAttribute(server, objectName); if (metricValue != null) { - // get the labels - Attributes attr = createLabels(server, objectName, extractor); + // get the metric attributes + Attributes attr = createMetricAttributes(server, objectName, extractor); measurement.record(metricValue.doubleValue(), attr); } } @@ -166,8 +166,8 @@ static Consumer longTypeCallback(MetricExtractor extr Number metricValue = extractor.getMetricValueExtractor().extractNumericalAttribute(server, objectName); if (metricValue != null) { - // get the labels - Attributes attr = createLabels(server, objectName, extractor); + // get the metric attributes + Attributes attr = createMetricAttributes(server, objectName, extractor); measurement.record(metricValue.longValue(), attr); } } @@ -176,17 +176,17 @@ static Consumer longTypeCallback(MetricExtractor extr } /* - * An auxiliary method for collecting labels (Measurement attributes) to go along + * An auxiliary method for collecting measurement attributes to go along * the metric values */ - static Attributes createLabels( + static Attributes createMetricAttributes( MBeanServer server, ObjectName objectName, MetricExtractor extractor) { - MetricLabel[] labels = extractor.getLabels(); + MetricAttribute[] metricAttributes = extractor.getAttributes(); AttributesBuilder attrBuilder = Attributes.builder(); - for (MetricLabel label : labels) { - String labelValue = label.extractLabelValue(server, objectName); - if (labelValue != null) { - attrBuilder = attrBuilder.put(label.getLabelName(), labelValue); + for (MetricAttribute metricAttribute : metricAttributes) { + String attributeValue = metricAttribute.acquireAttributeValue(server, objectName); + if (attributeValue != null) { + attrBuilder = attrBuilder.put(metricAttribute.getAttributeName(), attributeValue); } } return attrBuilder.build(); diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java index 10dd9ac96731..b0c8bed6e1ca 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java @@ -5,12 +5,12 @@ package io.opentelemetry.instrumentation.jmx.yaml; -import io.opentelemetry.instrumentation.jmx.engine.AttributeValueExtractor; +import io.opentelemetry.instrumentation.jmx.engine.BeanAttributeExtractor; import io.opentelemetry.instrumentation.jmx.engine.BeanPack; +import io.opentelemetry.instrumentation.jmx.engine.MetricAttribute; import io.opentelemetry.instrumentation.jmx.engine.MetricBanner; import io.opentelemetry.instrumentation.jmx.engine.MetricDef; import io.opentelemetry.instrumentation.jmx.engine.MetricExtractor; -import io.opentelemetry.instrumentation.jmx.engine.MetricLabel; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -99,11 +99,11 @@ private static Map validateAttributeMapping(Map } // Make sure that all attribute names are well-formed by creating the corresponding - // AttributeValueExtractors + // BeanAttributeExtractors Set attrNames = mapping.keySet(); for (String attributeName : attrNames) { - // check if AttributeValueExtractors can be built without exceptions - AttributeValueExtractor.fromName(attributeName); + // check if BeanAttributeExtractors can be built without exceptions + BeanAttributeExtractor.fromName(attributeName); } return mapping; } @@ -150,45 +150,47 @@ public MetricDef buildMetricDef() throws Exception { } else { banner = m.buildMetricBanner(prefix, attributeName, getUnit(), getMetricType()); } - AttributeValueExtractor attrExtractor = AttributeValueExtractor.fromName(attributeName); - - List labelList; - List ownLabels = getLabels(); - if (ownLabels != null && m != null && m.getLabels() != null) { - // MetricLabels have been specified at two levels, need to combine them - labelList = combineLabels(ownLabels, m.getLabels()); - } else if (ownLabels != null) { - labelList = ownLabels; - } else if (m != null && m.getLabels() != null) { - // Get the labels from the metric - labelList = m.getLabels(); + BeanAttributeExtractor attrExtractor = BeanAttributeExtractor.fromName(attributeName); + + List attributeList; + List ownAttributes = getAttributeList(); + if (ownAttributes != null && m != null && m.getAttributeList() != null) { + // MetricAttributes have been specified at two levels, need to combine them + attributeList = combineMetricAttributes(ownAttributes, m.getAttributeList()); + } else if (ownAttributes != null) { + attributeList = ownAttributes; + } else if (m != null && m.getAttributeList() != null) { + // Get the attributes from the metric + attributeList = m.getAttributeList(); } else { - // There are no labels at all - labelList = new ArrayList(); + // There are no attributes at all + attributeList = new ArrayList(); } MetricExtractor metricExtractor = new MetricExtractor( - attrExtractor, banner, labelList.toArray(new MetricLabel[labelList.size()])); + attrExtractor, + banner, + attributeList.toArray(new MetricAttribute[attributeList.size()])); metricExtractors[n++] = metricExtractor; } return new MetricDef(pack, metricExtractors); } - private static List combineLabels( - List ownLabels, List metricLabels) { - Map set = new HashMap<>(); - for (MetricLabel ownLabel : ownLabels) { - set.put(ownLabel.getLabelName(), ownLabel); + private static List combineMetricAttributes( + List ownAttributes, List metricAttributes) { + Map set = new HashMap<>(); + for (MetricAttribute ownAttribute : ownAttributes) { + set.put(ownAttribute.getAttributeName(), ownAttribute); } - // Let the metric level defined labels override own lables - for (MetricLabel metricLabel : metricLabels) { - set.put(metricLabel.getLabelName(), metricLabel); + // Let the metric level defined attributes override own attributes + for (MetricAttribute metricAttribute : metricAttributes) { + set.put(metricAttribute.getAttributeName(), metricAttribute); } - List result = new ArrayList(); + List result = new ArrayList(); result.addAll(set.values()); return result; } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java index f6cc52513fe3..8e4044db4a48 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java @@ -5,8 +5,8 @@ package io.opentelemetry.instrumentation.jmx.yaml; +import io.opentelemetry.instrumentation.jmx.engine.MetricAttribute; import io.opentelemetry.instrumentation.jmx.engine.MetricBanner; -import io.opentelemetry.instrumentation.jmx.engine.MetricLabel; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -14,26 +14,26 @@ /** * An abstract class containing skeletal info about Metrics: *

  • the metric type - *
  • the metric attributes (labels) + *
  • the metric attributes *
  • the unit * - *

    Known subclasses are JMXRule and Metric. + *

    Known subclasses are JmxRule and Metric. */ abstract class MetricStructure { // Used by the YAML parser // type: TYPE - // label: + // metricAttribute: // KEY1: SPECIFICATION1 // KEY2: SPECIFICATION2 // unit: UNIT private String type; // unused, for YAML parser only - private Map label; // unused, for YAML parser only + private Map metricAttribute; // unused, for YAML parser only private String unit; private MetricBanner.Type metricType; - private List labels; + private List metricAttributes; public String getType() { return type; @@ -60,30 +60,31 @@ private String validateUnit(String unit) { } /** - * When the YAML parser sets the labels, convert them immediately to MetricLabels. Any errors - * during conversion will show in the context of the parsed YAML file. + * When the YAML parser sets the metric attributes (as Strings), convert them immediately to + * MetricAttribute objects. Any errors during conversion will show in the context of the parsed + * YAML file. * - * @param label the mapping of metric attribute keys to evaluating snippets + * @param map the mapping of metric attribute keys to evaluating snippets */ - public void setLabel(Map label) { - this.label = label; - // pre-build the Labels - List labelList = new ArrayList<>(); - addLabels(labelList, label); - this.labels = labelList; + public void setMetricAttribute(Map map) { + this.metricAttribute = map; + // pre-build the MetricAttributes + List attrList = new ArrayList<>(); + addMetricAttributes(attrList, map); + this.metricAttributes = attrList; } // Used only for testing - public Map getLabel() { - return label; + public Map getMetricAttribute() { + return metricAttribute; } public MetricBanner.Type getMetricType() { return metricType; } - protected List getLabels() { - return labels; + protected List getAttributeList() { + return metricAttributes; } protected void requireNonEmpty(String s, String msg) { @@ -92,23 +93,25 @@ protected void requireNonEmpty(String s, String msg) { } } - private static void addLabels(List list, Map tagMap) { - if (tagMap != null) { - for (String key : tagMap.keySet()) { - String target = tagMap.get(key); + private static void addMetricAttributes( + List list, Map metricAttributeMap) { + if (metricAttributeMap != null) { + for (String key : metricAttributeMap.keySet()) { + String target = metricAttributeMap.get(key); if (target == null) { - throw new IllegalStateException("nothing specified for label key '" + key + "'"); + throw new IllegalStateException( + "nothing specified for metric attribute key '" + key + "'"); } - list.add(buildLabel(key, target.trim())); + list.add(buildMetricAttribute(key, target.trim())); } } } - private static MetricLabel buildLabel(String key, String target) { + private static MetricAttribute buildMetricAttribute(String key, String target) { // The recognized forms of target are: // - param(STRING) - // - attr(STRING) - // - STRING + // - beanattr(STRING) + // - const(STRING) // where STRING is the name of the corresponding parameter key, attribute name, // or the direct value to use int k = target.indexOf(')'); @@ -116,15 +119,21 @@ private static MetricLabel buildLabel(String key, String target) { // Check for one of the cases as above if (target.startsWith("param(")) { if (k > 0) { - return new MetricLabel(key, MetricLabel.fromParameter(target.substring(6, k).trim())); + return new MetricAttribute( + key, MetricAttribute.fromObjectNameParameter(target.substring(6, k).trim())); } - } else if (target.startsWith("attr(")) { + } else if (target.startsWith("beanattr(")) { if (k > 0) { - return new MetricLabel(key, MetricLabel.fromAttribute(target.substring(5, k).trim())); + return new MetricAttribute( + key, MetricAttribute.fromBeanAttribute(target.substring(9, k).trim())); + } + } else if (target.startsWith("const(")) { + if (k > 0) { + return new MetricAttribute( + key, MetricAttribute.fromConstant(target.substring(6, k).trim())); } - } else if (k < 0) { - return new MetricLabel(key, MetricLabel.fromConstant(target)); } - throw new IllegalArgumentException("Invalid label specification for '" + key + "'"); + + throw new IllegalArgumentException("Invalid metric attribute specification for '" + key + "'"); } } diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java index 249d9243224a..f268279d820e 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java @@ -102,7 +102,7 @@ void testSetup() throws Exception { @Test void testByteAttribute() throws Exception { - AttributeValueExtractor extractor = new AttributeValueExtractor("ByteAttribute"); + BeanAttributeExtractor extractor = new BeanAttributeExtractor("ByteAttribute"); AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); assertThat(info == null).isFalse(); assertThat(info.usesDoubleValues()).isFalse(); @@ -110,7 +110,7 @@ void testByteAttribute() throws Exception { @Test void testByteAttributeValue() throws Exception { - AttributeValueExtractor extractor = new AttributeValueExtractor("ByteAttribute"); + BeanAttributeExtractor extractor = new BeanAttributeExtractor("ByteAttribute"); Number number = extractor.extractNumericalAttribute(theServer, objectName); assertThat(number == null).isFalse(); assertThat(number.longValue() == 10).isTrue(); @@ -118,7 +118,7 @@ void testByteAttributeValue() throws Exception { @Test void testShortAttribute() throws Exception { - AttributeValueExtractor extractor = new AttributeValueExtractor("ShortAttribute"); + BeanAttributeExtractor extractor = new BeanAttributeExtractor("ShortAttribute"); AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); assertThat(info == null).isFalse(); assertThat(info.usesDoubleValues()).isFalse(); @@ -126,7 +126,7 @@ void testShortAttribute() throws Exception { @Test void testShortAttributeValue() throws Exception { - AttributeValueExtractor extractor = new AttributeValueExtractor("ShortAttribute"); + BeanAttributeExtractor extractor = new BeanAttributeExtractor("ShortAttribute"); Number number = extractor.extractNumericalAttribute(theServer, objectName); assertThat(number == null).isFalse(); assertThat(number.longValue() == 11).isTrue(); @@ -134,7 +134,7 @@ void testShortAttributeValue() throws Exception { @Test void testIntAttribute() throws Exception { - AttributeValueExtractor extractor = new AttributeValueExtractor("IntAttribute"); + BeanAttributeExtractor extractor = new BeanAttributeExtractor("IntAttribute"); AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); assertThat(info == null).isFalse(); assertThat(info.usesDoubleValues()).isFalse(); @@ -142,7 +142,7 @@ void testIntAttribute() throws Exception { @Test void testIntAttributeValue() throws Exception { - AttributeValueExtractor extractor = new AttributeValueExtractor("IntAttribute"); + BeanAttributeExtractor extractor = new BeanAttributeExtractor("IntAttribute"); Number number = extractor.extractNumericalAttribute(theServer, objectName); assertThat(number == null).isFalse(); assertThat(number.longValue() == 12).isTrue(); @@ -150,7 +150,7 @@ void testIntAttributeValue() throws Exception { @Test void testLongAttribute() throws Exception { - AttributeValueExtractor extractor = new AttributeValueExtractor("LongAttribute"); + BeanAttributeExtractor extractor = new BeanAttributeExtractor("LongAttribute"); AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); assertThat(info == null).isFalse(); assertThat(info.usesDoubleValues()).isFalse(); @@ -158,7 +158,7 @@ void testLongAttribute() throws Exception { @Test void testLongAttributeValue() throws Exception { - AttributeValueExtractor extractor = new AttributeValueExtractor("LongAttribute"); + BeanAttributeExtractor extractor = new BeanAttributeExtractor("LongAttribute"); Number number = extractor.extractNumericalAttribute(theServer, objectName); assertThat(number == null).isFalse(); assertThat(number.longValue() == 13).isTrue(); @@ -166,7 +166,7 @@ void testLongAttributeValue() throws Exception { @Test void testFloatAttribute() throws Exception { - AttributeValueExtractor extractor = new AttributeValueExtractor("FloatAttribute"); + BeanAttributeExtractor extractor = new BeanAttributeExtractor("FloatAttribute"); AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); assertThat(info == null).isFalse(); assertThat(info.usesDoubleValues()).isTrue(); @@ -174,7 +174,7 @@ void testFloatAttribute() throws Exception { @Test void testFloatAttributeValue() throws Exception { - AttributeValueExtractor extractor = new AttributeValueExtractor("FloatAttribute"); + BeanAttributeExtractor extractor = new BeanAttributeExtractor("FloatAttribute"); Number number = extractor.extractNumericalAttribute(theServer, objectName); assertThat(number == null).isFalse(); assertThat(number.doubleValue() == 14.0).isTrue(); // accurate representation @@ -182,7 +182,7 @@ void testFloatAttributeValue() throws Exception { @Test void testDoubleAttribute() throws Exception { - AttributeValueExtractor extractor = new AttributeValueExtractor("DoubleAttribute"); + BeanAttributeExtractor extractor = new BeanAttributeExtractor("DoubleAttribute"); AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); assertThat(info == null).isFalse(); assertThat(info.usesDoubleValues()).isTrue(); @@ -190,7 +190,7 @@ void testDoubleAttribute() throws Exception { @Test void testDoubleAttributeValue() throws Exception { - AttributeValueExtractor extractor = new AttributeValueExtractor("DoubleAttribute"); + BeanAttributeExtractor extractor = new BeanAttributeExtractor("DoubleAttribute"); Number number = extractor.extractNumericalAttribute(theServer, objectName); assertThat(number == null).isFalse(); assertThat(number.doubleValue() == 15.0).isTrue(); // accurate representation @@ -198,7 +198,7 @@ void testDoubleAttributeValue() throws Exception { @Test void testStringAttribute() throws Exception { - AttributeValueExtractor extractor = new AttributeValueExtractor("StringAttribute"); + BeanAttributeExtractor extractor = new BeanAttributeExtractor("StringAttribute"); AttributeInfo info = extractor.getAttributeInfo(theServer, objectName); assertThat(info == null).isTrue(); } diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java index b67025d8f0bf..c1e8698accec 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java @@ -42,9 +42,9 @@ static void setup() throws Exception { + " - beans:\n" + " - OBJECT:NAME1=*\n" + " - OBJECT:NAME2=*\n" - + " label:\n" + + " metricAttribute:\n" + " LABEL_KEY1: param(PARAMETER)\n" - + " LABEL_KEY2: attr(ATTRIBUTE)\n" + + " LABEL_KEY2: beanattr(ATTRIBUTE)\n" + " prefix: METRIC_NAME_PREFIX\n" + " mapping:\n" + " ATTRIBUTE1:\n" @@ -52,8 +52,8 @@ static void setup() throws Exception { + " type: Gauge\n" + " desc: DESCRIPTION1\n" + " unit: UNIT1\n" - + " label:\n" - + " LABEL_KEY3: CONSTANT\n" + + " metricAttribute:\n" + + " LABEL_KEY3: const(CONSTANT)\n" + " ATTRIBUTE2:\n" + " metric: METRIC_NAME2\n" + " desc: DESCRIPTION2\n" @@ -77,7 +77,7 @@ void testConf2() throws Exception { JmxRule def1 = defs.get(0); assertThat(def1.getBeans().size() == 2).isTrue(); - assertThat(def1.getLabel().size() == 2).isTrue(); + assertThat(def1.getMetricAttribute().size() == 2).isTrue(); Map attr = def1.getMapping(); assertThat(attr == null).isFalse(); assertThat(attr.size() == 4).isTrue(); @@ -87,9 +87,9 @@ void testConf2() throws Exception { assertThat("METRIC_NAME1".equals(m1.getMetric())).isTrue(); assertThat(m1.getMetricType() == MetricBanner.Type.GAUGE).isTrue(); assertThat("UNIT1".equals(m1.getUnit())).isTrue(); - assertThat(m1.getLabel() == null).isFalse(); - assertThat(m1.getLabel().size() == 1).isTrue(); - assertThat("CONSTANT".equals(m1.getLabel().get("LABEL_KEY3"))).isTrue(); + assertThat(m1.getMetricAttribute() == null).isFalse(); + assertThat(m1.getMetricAttribute().size() == 1).isTrue(); + assertThat("const(CONSTANT)".equals(m1.getMetricAttribute().get("LABEL_KEY3"))).isTrue(); } private static final String CONF3 = @@ -114,7 +114,7 @@ void testConf3() throws Exception { JmxRule def1 = defs.get(0); assertThat(def1.getBean() == null).isFalse(); - assertThat(def1.getLabel() == null).isTrue(); + assertThat(def1.getMetricAttribute() == null).isTrue(); Map attr = def1.getMapping(); assertThat(attr.size() == 5).isTrue(); @@ -131,9 +131,9 @@ void testConf3() throws Exception { "---\n" + "rules:\n" + " - bean: my-test:type=4\n" - + " label:\n" + + " metricAttribute:\n" + " LABEL_KEY1: param(PARAMETER)\n" - + " LABEL_KEY2: attr(ATTRIBUTE)\n" + + " LABEL_KEY2: beanattr(ATTRIBUTE)\n" + " prefix: PREFIX.\n" + " type: upDownCounter\n" + " unit: DEFAULT_UNIT\n" @@ -143,8 +143,8 @@ void testConf3() throws Exception { + " type: counter\n" + " desc: DESCRIPTION1\n" + " unit: UNIT1\n" - + " label:\n" - + " LABEL_KEY3: CONSTANT\n" + + " metricAttribute:\n" + + " LABEL_KEY3: const(CONSTANT)\n" + " ATTRIBUTE2:\n" + " metric: METRIC_NAME2\n" + " desc: DESCRIPTION2\n" @@ -165,9 +165,9 @@ void testConf4() throws Exception { assertThat(metricDef.getMetricExtractors().length == 3).isTrue(); MetricExtractor m1 = metricDef.getMetricExtractors()[0]; - AttributeValueExtractor a1 = m1.getMetricValueExtractor(); + BeanAttributeExtractor a1 = m1.getMetricValueExtractor(); assertThat("A.b".equals(a1.getAttributeName())).isTrue(); - assertThat(m1.getLabels().length == 3).isTrue(); + assertThat(m1.getAttributes().length == 3).isTrue(); MetricBanner mb1 = m1.getBanner(); assertThat("PREFIX.METRIC_NAME1".equals(mb1.getMetricName())).isTrue(); assertThat("DESCRIPTION1".equals(mb1.getDescription())).isTrue(); @@ -175,7 +175,7 @@ void testConf4() throws Exception { assertThat(MetricBanner.Type.COUNTER == mb1.getType()).isTrue(); MetricExtractor m3 = metricDef.getMetricExtractors()[2]; - AttributeValueExtractor a3 = m3.getMetricValueExtractor(); + BeanAttributeExtractor a3 = m3.getMetricValueExtractor(); assertThat("ATTRIBUTE3".equals(a3.getAttributeName())).isTrue(); MetricBanner mb3 = m3.getBanner(); assertThat("PREFIX.ATTRIBUTE3".equals(mb3.getMetricName())).isTrue(); @@ -205,25 +205,25 @@ void testConf5() throws Exception { assertThat(metricDef.getMetricExtractors().length == 1).isTrue(); MetricExtractor m1 = metricDef.getMetricExtractors()[0]; - AttributeValueExtractor a1 = m1.getMetricValueExtractor(); + BeanAttributeExtractor a1 = m1.getMetricValueExtractor(); assertThat("ATTRIBUTE".equals(a1.getAttributeName())).isTrue(); - assertThat(m1.getLabels().length == 0).isTrue(); + assertThat(m1.getAttributes().length == 0).isTrue(); MetricBanner mb1 = m1.getBanner(); assertThat("ATTRIBUTE".equals(mb1.getMetricName())).isTrue(); assertThat(MetricBanner.Type.GAUGE == mb1.getType()).isTrue(); assertThat(null == mb1.getUnit()).isTrue(); } - private static final String CONF6 = // merging label sets with same keys + private static final String CONF6 = // merging metric attribute sets with same keys "--- # keep stupid spotlessJava at bay\n" + "rules:\n" + " - bean: my-test:type=6\n" - + " label:\n" - + " key1: value1\n" + + " metricAttribute:\n" + + " key1: const(value1)\n" + " mapping:\n" + " ATTRIBUTE:\n" - + " label:\n" - + " key1: value2\n"; + + " metricAttribute:\n" + + " key1: const(value2)\n"; @Test void testConf6() throws Exception { @@ -239,26 +239,26 @@ void testConf6() throws Exception { assertThat(metricDef.getMetricExtractors().length == 1).isTrue(); MetricExtractor m1 = metricDef.getMetricExtractors()[0]; - AttributeValueExtractor a1 = m1.getMetricValueExtractor(); + BeanAttributeExtractor a1 = m1.getMetricValueExtractor(); assertThat("ATTRIBUTE".equals(a1.getAttributeName())).isTrue(); - // MetricLabel set at the metric level should override the one set at the definition level - assertThat(m1.getLabels().length == 1).isTrue(); - MetricLabel l1 = m1.getLabels()[0]; - assertThat("value2".equals(l1.extractLabelValue(null, null))).isTrue(); + // MetricAttribute set at the metric level should override the one set at the definition level + assertThat(m1.getAttributes().length == 1).isTrue(); + MetricAttribute l1 = m1.getAttributes()[0]; + assertThat("value2".equals(l1.acquireAttributeValue(null, null))).isTrue(); MetricBanner mb1 = m1.getBanner(); assertThat("ATTRIBUTE".equals(mb1.getMetricName())).isTrue(); } - private static final String CONF7 = // merging label sets with different keys + private static final String CONF7 = "--- # keep stupid spotlessJava at bay\n" + "rules:\n" + " - bean: my-test:type=7\n" - + " label:\n" - + " key1: value1\n" + + " metricAttribute:\n" + + " key1: const(value1)\n" + " mapping:\n" + " ATTRIBUTE:\n" - + " label:\n" - + " key2: value2\n"; + + " metricAttribute:\n" + + " key2: const(value2)\n"; @Test void testConf7() throws Exception { @@ -273,10 +273,11 @@ void testConf7() throws Exception { assertThat(metricDef == null).isFalse(); assertThat(metricDef.getMetricExtractors().length == 1).isTrue(); + // Test that the MBean attribute is correctly parsed MetricExtractor m1 = metricDef.getMetricExtractors()[0]; - AttributeValueExtractor a1 = m1.getMetricValueExtractor(); + BeanAttributeExtractor a1 = m1.getMetricValueExtractor(); assertThat("ATTRIBUTE".equals(a1.getAttributeName())).isTrue(); - assertThat(m1.getLabels().length == 2).isTrue(); + assertThat(m1.getAttributes().length == 2).isTrue(); MetricBanner mb1 = m1.getBanner(); assertThat("ATTRIBUTE".equals(mb1.getMetricName())).isTrue(); } @@ -362,8 +363,8 @@ void testInvalidTag() throws Exception { + " - bean: domain:name=you\n" + " mapping:\n" + " ATTRIB:\n" - + " label:\n" - + " LABEL: attrib(something)\n" + + " metricAttribute:\n" + + " LABEL: something\n" + " metric: METRIC_NAME\n"; runNegativeTest(yaml); } @@ -389,8 +390,8 @@ void testInvalidTagFromAttribute() throws Exception { + " - bean: domain:name=you\n" + " mapping:\n" + " ATTRIB:\n" - + " label:\n" - + " LABEL: attr(.used)\n" + + " metricAttribute:\n" + + " LABEL: beanattr(.used)\n" + " metric: METRIC_NAME\n"; runNegativeTest(yaml); } @@ -403,8 +404,8 @@ void testEmptyTagFromAttribute() throws Exception { + " - bean: domain:name=you\n" + " mapping:\n" + " ATTRIB:\n" - + " label:\n" - + " LABEL: attr( )\n" + + " metricAttribute:\n" + + " LABEL: beanattr( )\n" + " metric: METRIC_NAME\n"; runNegativeTest(yaml); } @@ -417,7 +418,7 @@ void testEmptyTagFromParameter() throws Exception { + " - bean: domain:name=you\n" + " mapping:\n" + " ATTRIB:\n" - + " label:\n" + + " metricAttribute:\n" + " LABEL: param( )\n" + " metric: METRIC_NAME\n"; runNegativeTest(yaml); @@ -455,8 +456,8 @@ void testMessedUpSyntax() throws Exception { + "rules:\n" + " - bean: domain:name=you\n" + " mapping:\n" - + " label: # not valid here\n" - + " key: value\n" + + " metricAttribute: # not valid here\n" + + " key: const(value)\n" + " A:\n" + " metric: METRIC_NAME\n"; runNegativeTest(yaml); From 252be4593b0a97a8fa9ff58d67a9d28e23f205c1 Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Mon, 31 Oct 2022 12:14:06 -0700 Subject: [PATCH 14/20] Refining comments --- .../jmx/engine/MetricAttributeExtractor.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttributeExtractor.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttributeExtractor.java index 4480a7e86837..851e0f52a0a3 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttributeExtractor.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttributeExtractor.java @@ -14,5 +14,14 @@ */ public interface MetricAttributeExtractor { + /** + * Provide a String value to be used as the value of a metric attribute. + * + * @param server MBeanServer to query, must not be null if the extraction is from an MBean + * attribute + * @param objectName the identifier of the MBean to query, must not be null if the extraction is + * from an MBean attribute, or from the ObjectName parameter + * @return the value of the attribute, can be null if extraction failed + */ String extractValue(MBeanServer server, ObjectName objectName); } From 830a18f9553d2b726b2470b822843455be1fe59c Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Thu, 3 Nov 2022 13:57:36 -0700 Subject: [PATCH 15/20] Post-review code changes --- .../jmx/JmxMetricInsightInstaller.java | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java b/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java index 9abea4288e6d..5afb57697e81 100644 --- a/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java +++ b/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java @@ -5,8 +5,8 @@ package io.opentelemetry.instrumentation.javaagent.jmx; -import static java.util.logging.Level.CONFIG; import static java.util.logging.Level.FINE; +import static java.util.logging.Level.INFO; import com.google.auto.service.AutoService; import io.opentelemetry.api.GlobalOpenTelemetry; @@ -31,7 +31,7 @@ public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { if (config.getBoolean("otel.jmx.enabled", true)) { JmxMetricInsight service = JmxMetricInsight.createService(GlobalOpenTelemetry.get(), beanDiscoveryDelay(config)); - MetricConfiguration conf = buildMetricConfiguration(); + MetricConfiguration conf = buildMetricConfiguration(config); service.start(conf); } } @@ -61,26 +61,28 @@ private static void addRulesForPlatform(String platform, MetricConfiguration con RuleParser parserInstance = RuleParser.get(); parserInstance.addMetricDefs(conf, inputStream); } else { - JmxMetricInsight.getLogger().log(CONFIG, "No support found for {0}", platform); + JmxMetricInsight.getLogger().log(INFO, "No support found for {0}", platform); } } catch (Exception e) { JmxMetricInsight.getLogger().warning(e.getMessage()); } } - private static void buildFromDefaultRules(MetricConfiguration conf) { - String targetSystem = System.getProperty("otel.jmx.target.system", "").trim(); - String[] platforms = targetSystem.length() == 0 ? new String[0] : targetSystem.split(","); + private static void buildFromDefaultRules( + MetricConfiguration conf, ConfigProperties configProperties) { + String targetSystem = configProperties.getString("otel.jmx.target.system", ""); + String[] platforms = targetSystem.isEmpty() ? new String[0] : targetSystem.split(","); for (String platform : platforms) { addRulesForPlatform(platform, conf); } } - private static void buildFromUserRules(MetricConfiguration conf) { - String jmxDir = System.getProperty("otel.jmx.config"); + private static void buildFromUserRules( + MetricConfiguration conf, ConfigProperties configProperties) { + String jmxDir = configProperties.getString("otel.jmx.config"); if (jmxDir != null) { - JmxMetricInsight.getLogger().log(CONFIG, "JMX config file name: {0}", jmxDir); + JmxMetricInsight.getLogger().log(FINE, "JMX config file name: {0}", jmxDir); RuleParser parserInstance = RuleParser.get(); try (InputStream inputStream = Files.newInputStream(new File(jmxDir.trim()).toPath())) { parserInstance.addMetricDefs(conf, inputStream); @@ -90,13 +92,13 @@ private static void buildFromUserRules(MetricConfiguration conf) { } } - private static MetricConfiguration buildMetricConfiguration() { - MetricConfiguration conf = new MetricConfiguration(); + private static MetricConfiguration buildMetricConfiguration(ConfigProperties configProperties) { + MetricConfiguration metricConfiguration = new MetricConfiguration(); - buildFromDefaultRules(conf); + buildFromDefaultRules(metricConfiguration, configProperties); - buildFromUserRules(conf); + buildFromUserRules(metricConfiguration, configProperties); - return conf; + return metricConfiguration; } } From fcd6ca08336fa5d5b5452fb532c26a05ccf7185b Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Thu, 3 Nov 2022 14:46:23 -0700 Subject: [PATCH 16/20] Revert "Post-review code changes" committed by mistake This reverts commit 0c93fe5b66ed4f13ed480a0a96a7669a48f688a6. --- .../jmx/JmxMetricInsightInstaller.java | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java b/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java index 5afb57697e81..9abea4288e6d 100644 --- a/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java +++ b/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java @@ -5,8 +5,8 @@ package io.opentelemetry.instrumentation.javaagent.jmx; +import static java.util.logging.Level.CONFIG; import static java.util.logging.Level.FINE; -import static java.util.logging.Level.INFO; import com.google.auto.service.AutoService; import io.opentelemetry.api.GlobalOpenTelemetry; @@ -31,7 +31,7 @@ public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { if (config.getBoolean("otel.jmx.enabled", true)) { JmxMetricInsight service = JmxMetricInsight.createService(GlobalOpenTelemetry.get(), beanDiscoveryDelay(config)); - MetricConfiguration conf = buildMetricConfiguration(config); + MetricConfiguration conf = buildMetricConfiguration(); service.start(conf); } } @@ -61,28 +61,26 @@ private static void addRulesForPlatform(String platform, MetricConfiguration con RuleParser parserInstance = RuleParser.get(); parserInstance.addMetricDefs(conf, inputStream); } else { - JmxMetricInsight.getLogger().log(INFO, "No support found for {0}", platform); + JmxMetricInsight.getLogger().log(CONFIG, "No support found for {0}", platform); } } catch (Exception e) { JmxMetricInsight.getLogger().warning(e.getMessage()); } } - private static void buildFromDefaultRules( - MetricConfiguration conf, ConfigProperties configProperties) { - String targetSystem = configProperties.getString("otel.jmx.target.system", ""); - String[] platforms = targetSystem.isEmpty() ? new String[0] : targetSystem.split(","); + private static void buildFromDefaultRules(MetricConfiguration conf) { + String targetSystem = System.getProperty("otel.jmx.target.system", "").trim(); + String[] platforms = targetSystem.length() == 0 ? new String[0] : targetSystem.split(","); for (String platform : platforms) { addRulesForPlatform(platform, conf); } } - private static void buildFromUserRules( - MetricConfiguration conf, ConfigProperties configProperties) { - String jmxDir = configProperties.getString("otel.jmx.config"); + private static void buildFromUserRules(MetricConfiguration conf) { + String jmxDir = System.getProperty("otel.jmx.config"); if (jmxDir != null) { - JmxMetricInsight.getLogger().log(FINE, "JMX config file name: {0}", jmxDir); + JmxMetricInsight.getLogger().log(CONFIG, "JMX config file name: {0}", jmxDir); RuleParser parserInstance = RuleParser.get(); try (InputStream inputStream = Files.newInputStream(new File(jmxDir.trim()).toPath())) { parserInstance.addMetricDefs(conf, inputStream); @@ -92,13 +90,13 @@ private static void buildFromUserRules( } } - private static MetricConfiguration buildMetricConfiguration(ConfigProperties configProperties) { - MetricConfiguration metricConfiguration = new MetricConfiguration(); + private static MetricConfiguration buildMetricConfiguration() { + MetricConfiguration conf = new MetricConfiguration(); - buildFromDefaultRules(metricConfiguration, configProperties); + buildFromDefaultRules(conf); - buildFromUserRules(metricConfiguration, configProperties); + buildFromUserRules(conf); - return metricConfiguration; + return conf; } } From 5afd3ce4404a6b52b01a23225052ff824e59677d Mon Sep 17 00:00:00 2001 From: PeterF778 Date: Thu, 3 Nov 2022 14:57:51 -0700 Subject: [PATCH 17/20] Post-review code changes --- .../jmx/JmxMetricInsightInstaller.java | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java b/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java index 9abea4288e6d..5afb57697e81 100644 --- a/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java +++ b/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java @@ -5,8 +5,8 @@ package io.opentelemetry.instrumentation.javaagent.jmx; -import static java.util.logging.Level.CONFIG; import static java.util.logging.Level.FINE; +import static java.util.logging.Level.INFO; import com.google.auto.service.AutoService; import io.opentelemetry.api.GlobalOpenTelemetry; @@ -31,7 +31,7 @@ public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { if (config.getBoolean("otel.jmx.enabled", true)) { JmxMetricInsight service = JmxMetricInsight.createService(GlobalOpenTelemetry.get(), beanDiscoveryDelay(config)); - MetricConfiguration conf = buildMetricConfiguration(); + MetricConfiguration conf = buildMetricConfiguration(config); service.start(conf); } } @@ -61,26 +61,28 @@ private static void addRulesForPlatform(String platform, MetricConfiguration con RuleParser parserInstance = RuleParser.get(); parserInstance.addMetricDefs(conf, inputStream); } else { - JmxMetricInsight.getLogger().log(CONFIG, "No support found for {0}", platform); + JmxMetricInsight.getLogger().log(INFO, "No support found for {0}", platform); } } catch (Exception e) { JmxMetricInsight.getLogger().warning(e.getMessage()); } } - private static void buildFromDefaultRules(MetricConfiguration conf) { - String targetSystem = System.getProperty("otel.jmx.target.system", "").trim(); - String[] platforms = targetSystem.length() == 0 ? new String[0] : targetSystem.split(","); + private static void buildFromDefaultRules( + MetricConfiguration conf, ConfigProperties configProperties) { + String targetSystem = configProperties.getString("otel.jmx.target.system", ""); + String[] platforms = targetSystem.isEmpty() ? new String[0] : targetSystem.split(","); for (String platform : platforms) { addRulesForPlatform(platform, conf); } } - private static void buildFromUserRules(MetricConfiguration conf) { - String jmxDir = System.getProperty("otel.jmx.config"); + private static void buildFromUserRules( + MetricConfiguration conf, ConfigProperties configProperties) { + String jmxDir = configProperties.getString("otel.jmx.config"); if (jmxDir != null) { - JmxMetricInsight.getLogger().log(CONFIG, "JMX config file name: {0}", jmxDir); + JmxMetricInsight.getLogger().log(FINE, "JMX config file name: {0}", jmxDir); RuleParser parserInstance = RuleParser.get(); try (InputStream inputStream = Files.newInputStream(new File(jmxDir.trim()).toPath())) { parserInstance.addMetricDefs(conf, inputStream); @@ -90,13 +92,13 @@ private static void buildFromUserRules(MetricConfiguration conf) { } } - private static MetricConfiguration buildMetricConfiguration() { - MetricConfiguration conf = new MetricConfiguration(); + private static MetricConfiguration buildMetricConfiguration(ConfigProperties configProperties) { + MetricConfiguration metricConfiguration = new MetricConfiguration(); - buildFromDefaultRules(conf); + buildFromDefaultRules(metricConfiguration, configProperties); - buildFromUserRules(conf); + buildFromUserRules(metricConfiguration, configProperties); - return conf; + return metricConfiguration; } } From 87f166a15555d71ea5b261881282ae128ba236af Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Mon, 7 Nov 2022 14:09:43 -0800 Subject: [PATCH 18/20] Post-review code changes, renaming, more comments. --- .../jmx/JmxMetricInsightInstaller.java | 4 +- .../jmx/engine/AttributeInfo.java | 7 +- .../jmx/engine/BeanAttributeExtractor.java | 7 ++ .../instrumentation/jmx/engine/BeanPack.java | 6 +- .../jmx/engine/JmxMetricInsight.java | 4 +- .../jmx/engine/MetricAttribute.java | 19 ------ .../jmx/engine/MetricAttributeExtractor.java | 23 ++++++- .../jmx/engine/MetricBanner.java | 11 ++- .../instrumentation/jmx/engine/MetricDef.java | 68 ++++++++++++++++--- .../jmx/engine/MetricExtractor.java | 5 +- .../jmx/engine/MetricRegistrar.java | 8 +-- .../instrumentation/jmx/yaml/JmxConfig.java | 2 +- .../jmx/yaml/MetricStructure.java | 7 +- .../instrumentation/jmx/yaml/RuleParser.java | 8 +-- 14 files changed, 125 insertions(+), 54 deletions(-) diff --git a/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java b/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java index 5afb57697e81..89cde5ae5db9 100644 --- a/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java +++ b/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java @@ -59,7 +59,7 @@ private static void addRulesForPlatform(String platform, MetricConfiguration con if (inputStream != null) { JmxMetricInsight.getLogger().log(FINE, "Opened input stream {0}", yamlResource); RuleParser parserInstance = RuleParser.get(); - parserInstance.addMetricDefs(conf, inputStream); + parserInstance.addMetricDefsTo(conf, inputStream); } else { JmxMetricInsight.getLogger().log(INFO, "No support found for {0}", platform); } @@ -85,7 +85,7 @@ private static void buildFromUserRules( JmxMetricInsight.getLogger().log(FINE, "JMX config file name: {0}", jmxDir); RuleParser parserInstance = RuleParser.get(); try (InputStream inputStream = Files.newInputStream(new File(jmxDir.trim()).toPath())) { - parserInstance.addMetricDefs(conf, inputStream); + parserInstance.addMetricDefsTo(conf, inputStream); } catch (Exception e) { JmxMetricInsight.getLogger().warning(e.getMessage()); } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java index 01b68bb13869..ac1f8b6d0c4c 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/AttributeInfo.java @@ -5,6 +5,8 @@ package io.opentelemetry.instrumentation.jmx.engine; +import javax.annotation.Nullable; + /** * A class holding relevant information about an MBean attribute which will be used for collecting * metric values. The info comes directly from the relevant MBeans. @@ -12,9 +14,9 @@ class AttributeInfo { private boolean usesDoubles; - private String description; + @Nullable private String description; - AttributeInfo(Number sampleValue, String description) { + AttributeInfo(Number sampleValue, @Nullable String description) { if (sampleValue instanceof Byte || sampleValue instanceof Short || sampleValue instanceof Integer @@ -31,6 +33,7 @@ boolean usesDoubleValues() { return usesDoubles; } + @Nullable String getDescription() { return description; } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanAttributeExtractor.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanAttributeExtractor.java index bfa9e3e01c91..d68f730de28e 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanAttributeExtractor.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanAttributeExtractor.java @@ -10,6 +10,7 @@ import java.util.logging.Level; import java.util.logging.Logger; +import javax.annotation.Nullable; import javax.management.InstanceNotFoundException; import javax.management.MBeanAttributeInfo; import javax.management.MBeanInfo; @@ -98,6 +99,7 @@ String getAttributeName() { * @param objectName the ObjectName identifying the MBean * @return AttributeInfo if the attribute is properly recognized, or null */ + @Nullable AttributeInfo getAttributeInfo(MBeanServer server, ObjectName objectName) { if (logger.isLoggable(FINE)) { logger.log(FINE, "Resolving {0} for {1}", new Object[] {getAttributeName(), objectName}); @@ -168,6 +170,7 @@ AttributeInfo getAttributeInfo(MBeanServer server, ObjectName objectName) { * malfunctions will be silent to avoid flooding the log. * @return the attribute value, if found, or null if an error occurred */ + @Nullable private Object extractAttributeValue(MBeanServer server, ObjectName objectName, Logger logger) { try { Object value = server.getAttribute(objectName, baseName); @@ -206,10 +209,12 @@ private Object extractAttributeValue(MBeanServer server, ObjectName objectName, return null; } + @Nullable private Object extractAttributeValue(MBeanServer server, ObjectName objectName) { return extractAttributeValue(server, objectName, null); } + @Nullable Number extractNumericalAttribute(MBeanServer server, ObjectName objectName) { Object value = extractAttributeValue(server, objectName); if (value instanceof Number) { @@ -219,10 +224,12 @@ Number extractNumericalAttribute(MBeanServer server, ObjectName objectName) { } @Override + @Nullable public String extractValue(MBeanServer server, ObjectName objectName) { return extractStringAttribute(server, objectName); } + @Nullable private String extractStringAttribute(MBeanServer server, ObjectName objectName) { Object value = extractAttributeValue(server, objectName); if (value instanceof String) { diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java index d0b2143712c8..8bef01c07e57 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java @@ -5,6 +5,7 @@ package io.opentelemetry.instrumentation.jmx.engine; +import javax.annotation.Nullable; import javax.management.ObjectName; import javax.management.QueryExp; @@ -14,7 +15,7 @@ */ public class BeanPack { // How to specify the MBean(s) - private final QueryExp queryExp; + @Nullable private final QueryExp queryExp; private final ObjectName[] namePatterns; /** @@ -24,11 +25,12 @@ public class BeanPack { * @param namePatterns an array of ObjectNames used to look for MBeans; usually they will be * patterns. If multiple patterns are provided, they work as logical OR. */ - public BeanPack(QueryExp queryExp, ObjectName... namePatterns) { + public BeanPack(@Nullable QueryExp queryExp, ObjectName... namePatterns) { this.queryExp = queryExp; this.namePatterns = namePatterns; } + @Nullable QueryExp getQueryExp() { return queryExp; } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java index 3a6b82f484de..44fe4e7269e0 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/JmxMetricInsight.java @@ -5,7 +5,7 @@ package io.opentelemetry.instrumentation.jmx.engine; -import static java.util.logging.Level.CONFIG; +import static java.util.logging.Level.INFO; import io.opentelemetry.api.OpenTelemetry; import java.util.logging.Logger; @@ -36,7 +36,7 @@ private JmxMetricInsight(OpenTelemetry openTelemetry, long discoveryDelay) { public void start(MetricConfiguration conf) { if (conf.isEmpty()) { logger.log( - CONFIG, + INFO, "Empty JMX configuration, no metrics will be collected for InstrumentationScope " + INSTRUMENTATION_SCOPE); } else { diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttribute.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttribute.java index bdef32f65174..2dfff5509752 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttribute.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttribute.java @@ -29,23 +29,4 @@ public String getAttributeName() { String acquireAttributeValue(MBeanServer server, ObjectName objectName) { return extractor.extractValue(server, objectName); } - - public static MetricAttributeExtractor fromConstant(String constantValue) { - return (a, b) -> { - return constantValue; - }; - } - - public static MetricAttributeExtractor fromObjectNameParameter(String parameterKey) { - if (parameterKey.isEmpty()) { - throw new IllegalArgumentException("Empty parameter name"); - } - return (dummy, objectName) -> { - return objectName.getKeyProperty(parameterKey); - }; - } - - public static MetricAttributeExtractor fromBeanAttribute(String attributeName) { - return BeanAttributeExtractor.fromName(attributeName); - } } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttributeExtractor.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttributeExtractor.java index 851e0f52a0a3..61c9bc03c283 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttributeExtractor.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricAttributeExtractor.java @@ -5,6 +5,7 @@ package io.opentelemetry.instrumentation.jmx.engine; +import javax.annotation.Nullable; import javax.management.MBeanServer; import javax.management.ObjectName; @@ -23,5 +24,25 @@ public interface MetricAttributeExtractor { * from an MBean attribute, or from the ObjectName parameter * @return the value of the attribute, can be null if extraction failed */ - String extractValue(MBeanServer server, ObjectName objectName); + @Nullable + String extractValue(@Nullable MBeanServer server, @Nullable ObjectName objectName); + + static MetricAttributeExtractor fromConstant(String constantValue) { + return (a, b) -> { + return constantValue; + }; + } + + static MetricAttributeExtractor fromObjectNameParameter(String parameterKey) { + if (parameterKey.isEmpty()) { + throw new IllegalArgumentException("Empty parameter name"); + } + return (dummy, objectName) -> { + return objectName.getKeyProperty(parameterKey); + }; + } + + static MetricAttributeExtractor fromBeanAttribute(String attributeName) { + return BeanAttributeExtractor.fromName(attributeName); + } } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java index 57b5c41c421d..19480843f6b6 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java @@ -5,6 +5,8 @@ package io.opentelemetry.instrumentation.jmx.engine; +import javax.annotation.Nullable; + /** * A class providing the user visible characteristics (name, type, description and units) of a * metric to be reported with OpenTelemetry. @@ -22,8 +24,8 @@ public enum Type { // How to report the metric using OpenTelemetry API private final String metricName; // used as Instrument name - private final String description; - private final String unit; + @Nullable private final String description; + @Nullable private final String unit; private final Type type; /** @@ -34,7 +36,8 @@ public enum Type { * @param unit a human readable unit of measurement * @param type the instrument typ to be used for the metric */ - public MetricBanner(String metricName, String description, String unit, Type type) { + public MetricBanner( + String metricName, @Nullable String description, String unit, @Nullable Type type) { this.metricName = metricName; this.description = description; this.unit = unit; @@ -45,10 +48,12 @@ String getMetricName() { return metricName; } + @Nullable String getDescription() { return description; } + @Nullable String getUnit() { return unit; } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java index 8f40e9bb3e51..f08e5a74bd50 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java @@ -9,17 +9,65 @@ * A class providing a complete definition on how to create an Open Telemetry metric out of the JMX * system: how to extract values from MBeans and how to model, name and decorate them with * attributes using OpenTelemetry Metric API. Objects of this class are immutable. - * - *

    Example: The JVM provides an MBean with ObjectName "java.lang:type=Threading", and one of the - * MBean attributes is "ThreadCount". This MBean can be used to provide a metric showing the current - * number of threads run by the JVM as follows: - * - *

    new MetricDef(new BeanPack(null, new ObjectName("java.lang:type=Threading")), - * - *

    new MetricExtractor(new BeanAttributeExtractor("ThreadCount"), - * - *

    new MetricBanner("process.runtime.jvm.threads", "Current number of threads", "1" ))); */ + +// Example: The rule described by the following YAML definition +// +// - bean: java.lang:name=*,type=MemoryPool +// metricAttribute: +// pool: param(name) +// type: beanattr(Type) +// mapping: +// Usage.used: +// metric: my.own.jvm.memory.pool.used +// type: updowncounter +// desc: Pool memory currently used +// unit: By +// Usage.max: +// metric: my.own.jvm.memory.pool.max +// type: updowncounter +// desc: Maximum obtainable memory pool size +// unit: By +// +// can be created using the following snippet: +// +// MetricAttribute poolAttribute = +// new MetricAttribute("pool", MetricAttributeExtractor.fromObjectNameParameter("name")); +// MetricAttribute typeAttribute = +// new MetricAttribute("type", MetricAttributeExtractor.fromBeanAttribute("Type")); +// +// MetricBanner poolUsedBanner = +// new MetricBanner( +// "my.own.jvm.memory.pool.used", +// "Pool memory currently used", +// "By", +// MetricBanner.Type.UPDOWNCOUNTER); +// MetricBanner poolLimitBanner = +// new MetricBanner( +// "my.own.jvm.memory.pool.limit", +// "Maximum obtainable memory pool size", +// "By", +// MetricBanner.Type.UPDOWNCOUNTER); +// +// MetricExtractor usageUsedExtractor = +// new MetricExtractor( +// new BeanAttributeExtractor("Usage", "used"), +// poolUsedBanner, +// poolAttribute, +// typeAttribute); +// MetricExtractor usageMaxExtractor = +// new MetricExtractor( +// new BeanAttributeExtractor("Usage", "max"), +// poolLimitBanner, +// poolAttribute, +// typeAttribute); +// +// MetricDef def = +// new MetricDef( +// new BeanPack(null, new ObjectName("java.lang:name=*,type=MemoryPool")), +// usageUsedExtractor, +// usageMaxExtractor); + public class MetricDef { // Describes the MBeans to use diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java index 6d49081de9dd..6539c6076e3c 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java @@ -5,6 +5,8 @@ package io.opentelemetry.instrumentation.jmx.engine; +import javax.annotation.Nullable; + /** * A class holding the info needed to support a single metric: how to define it in OpenTelemetry and * how to provide the metric values. @@ -22,7 +24,7 @@ public class MetricExtractor { // Defines the Measurement attributes to be used when reporting the metric value. private final MetricAttribute[] attributes; - private volatile DetectionStatus status; + @Nullable private volatile DetectionStatus status; public MetricExtractor( BeanAttributeExtractor attributeExtractor, @@ -49,6 +51,7 @@ void setStatus(DetectionStatus status) { this.status = status; } + @Nullable DetectionStatus getStatus() { return status; } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java index 49ac9f2676ed..d207e317b21b 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java @@ -5,7 +5,7 @@ package io.opentelemetry.instrumentation.jmx.engine; -import static java.util.logging.Level.CONFIG; +import static java.util.logging.Level.INFO; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.Attributes; @@ -83,7 +83,7 @@ void enrollExtractor( } else { builder.buildWithCallback(longTypeCallback(extractor)); } - logger.log(CONFIG, "Created Counter for {0}", metricName); + logger.log(INFO, "Created Counter for {0}", metricName); } break; @@ -104,7 +104,7 @@ void enrollExtractor( } else { builder.buildWithCallback(longTypeCallback(extractor)); } - logger.log(CONFIG, "Created UpDownCounter for {0}", metricName); + logger.log(INFO, "Created UpDownCounter for {0}", metricName); } break; @@ -125,7 +125,7 @@ void enrollExtractor( } else { builder.ofLongs().buildWithCallback(longTypeCallback(extractor)); } - logger.log(CONFIG, "Created Gauge for {0}", metricName); + logger.log(INFO, "Created Gauge for {0}", metricName); } } } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java index 1749a098310c..d979dfb75752 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxConfig.java @@ -37,7 +37,7 @@ public void setRules(List rules) { * @param configuration MetricConfiguration to add MetricDefs to * @throws an exception if the rule conversion cannot be performed */ - public void addMetricDefs(MetricConfiguration configuration) throws Exception { + void addMetricDefsTo(MetricConfiguration configuration) throws Exception { for (JmxRule rule : rules) { MetricDef metricDef = rule.buildMetricDef(); configuration.addMetricDef(metricDef); diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java index 8e4044db4a48..026a09a285a9 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java @@ -6,6 +6,7 @@ package io.opentelemetry.instrumentation.jmx.yaml; import io.opentelemetry.instrumentation.jmx.engine.MetricAttribute; +import io.opentelemetry.instrumentation.jmx.engine.MetricAttributeExtractor; import io.opentelemetry.instrumentation.jmx.engine.MetricBanner; import java.util.ArrayList; import java.util.List; @@ -120,17 +121,17 @@ private static MetricAttribute buildMetricAttribute(String key, String target) { if (target.startsWith("param(")) { if (k > 0) { return new MetricAttribute( - key, MetricAttribute.fromObjectNameParameter(target.substring(6, k).trim())); + key, MetricAttributeExtractor.fromObjectNameParameter(target.substring(6, k).trim())); } } else if (target.startsWith("beanattr(")) { if (k > 0) { return new MetricAttribute( - key, MetricAttribute.fromBeanAttribute(target.substring(9, k).trim())); + key, MetricAttributeExtractor.fromBeanAttribute(target.substring(9, k).trim())); } } else if (target.startsWith("const(")) { if (k > 0) { return new MetricAttribute( - key, MetricAttribute.fromConstant(target.substring(6, k).trim())); + key, MetricAttributeExtractor.fromConstant(target.substring(6, k).trim())); } } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java index d200db1a9537..c5080db7b500 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java @@ -5,7 +5,7 @@ package io.opentelemetry.instrumentation.jmx.yaml; -import static java.util.logging.Level.CONFIG; +import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration; @@ -52,13 +52,13 @@ public JmxConfig loadConfig(InputStream is) throws Exception { * @param conf the metric configuration * @param is the InputStream with the YAML rules */ - public void addMetricDefs(MetricConfiguration conf, InputStream is) { + public void addMetricDefsTo(MetricConfiguration conf, InputStream is) { try { JmxConfig config = loadConfig(is); if (config != null) { - logger.log(CONFIG, "Found {0} metric rules", config.getRules().size()); - config.addMetricDefs(conf); + logger.log(INFO, "Found {0} metric rules", config.getRules().size()); + config.addMetricDefsTo(conf); } } catch (Exception exception) { logger.log(WARNING, "Failed to parse YAML rules: " + rootCause(exception)); From a3b40f3a6b66078b57cdbb135c90a824cb542171 Mon Sep 17 00:00:00 2001 From: Peter Findeisen Date: Wed, 9 Nov 2022 15:17:04 -0800 Subject: [PATCH 19/20] Post-review code changes, more renaming. --- .../instrumentation/jmx/engine/MetricDef.java | 16 ++++++++-------- .../jmx/engine/MetricExtractor.java | 10 +++++----- .../{MetricBanner.java => MetricInfo.java} | 6 +++--- .../jmx/engine/MetricRegistrar.java | 12 ++++++------ .../instrumentation/jmx/yaml/JmxRule.java | 12 ++++++------ .../instrumentation/jmx/yaml/Metric.java | 10 +++++----- .../jmx/yaml/MetricStructure.java | 8 ++++---- .../jmx/engine/AttributeExtractorTest.java | 4 ++-- .../jmx/engine/RuleParserTest.java | 18 +++++++++--------- 9 files changed, 48 insertions(+), 48 deletions(-) rename instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/{MetricBanner.java => MetricInfo.java} (94%) diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java index f08e5a74bd50..4107a80f83e7 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java @@ -36,29 +36,29 @@ // MetricAttribute typeAttribute = // new MetricAttribute("type", MetricAttributeExtractor.fromBeanAttribute("Type")); // -// MetricBanner poolUsedBanner = -// new MetricBanner( +// MetricInfo poolUsedInfo = +// new MetricInfo( // "my.own.jvm.memory.pool.used", // "Pool memory currently used", // "By", -// MetricBanner.Type.UPDOWNCOUNTER); -// MetricBanner poolLimitBanner = -// new MetricBanner( +// MetricInfo.Type.UPDOWNCOUNTER); +// MetricInfo poolLimitInfo = +// new MetricInfo( // "my.own.jvm.memory.pool.limit", // "Maximum obtainable memory pool size", // "By", -// MetricBanner.Type.UPDOWNCOUNTER); +// MetricInfo.Type.UPDOWNCOUNTER); // // MetricExtractor usageUsedExtractor = // new MetricExtractor( // new BeanAttributeExtractor("Usage", "used"), -// poolUsedBanner, +// poolUsedInfo, // poolAttribute, // typeAttribute); // MetricExtractor usageMaxExtractor = // new MetricExtractor( // new BeanAttributeExtractor("Usage", "max"), -// poolLimitBanner, +// poolLimitInfo, // poolAttribute, // typeAttribute); // diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java index 6539c6076e3c..2b9ce939168d 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricExtractor.java @@ -16,7 +16,7 @@ */ public class MetricExtractor { - private final MetricBanner banner; + private final MetricInfo metricInfo; // Defines the way to access the metric value (a number) private final BeanAttributeExtractor attributeExtractor; @@ -28,15 +28,15 @@ public class MetricExtractor { public MetricExtractor( BeanAttributeExtractor attributeExtractor, - MetricBanner banner, + MetricInfo metricInfo, MetricAttribute... attributes) { this.attributeExtractor = attributeExtractor; - this.banner = banner; + this.metricInfo = metricInfo; this.attributes = attributes; } - MetricBanner getBanner() { - return banner; + MetricInfo getInfo() { + return metricInfo; } BeanAttributeExtractor getMetricValueExtractor() { diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricInfo.java similarity index 94% rename from instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricInfo.java index 19480843f6b6..fed1935ca764 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricBanner.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricInfo.java @@ -13,7 +13,7 @@ * *

    Objects of this class are immutable. */ -public class MetricBanner { +public class MetricInfo { // OpenTelemetry asynchronous instrument types that can be used public enum Type { @@ -29,14 +29,14 @@ public enum Type { private final Type type; /** - * Constructor for MetricBanner. + * Constructor for MetricInfo. * * @param metricName a String that will be used as a metric name, it should be unique * @param description a human readable description of the metric * @param unit a human readable unit of measurement * @param type the instrument typ to be used for the metric */ - public MetricBanner( + public MetricInfo( String metricName, @Nullable String description, String unit, @Nullable Type type) { this.metricName = metricName; this.description = description; diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java index d207e317b21b..58bec6fb3887 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java @@ -56,14 +56,14 @@ void enrollExtractor( } if (firstEnrollment) { - MetricBanner banner = extractor.getBanner(); - String metricName = banner.getMetricName(); - MetricBanner.Type instrumentType = banner.getType(); + MetricInfo metricInfo = extractor.getInfo(); + String metricName = metricInfo.getMetricName(); + MetricInfo.Type instrumentType = metricInfo.getType(); String description = - banner.getDescription() != null - ? banner.getDescription() + metricInfo.getDescription() != null + ? metricInfo.getDescription() : attributeInfo.getDescription(); - String unit = banner.getUnit(); + String unit = metricInfo.getUnit(); switch (instrumentType) { // CHECKSTYLE:OFF diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java index b0c8bed6e1ca..3d94f490c1a7 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java @@ -8,9 +8,9 @@ import io.opentelemetry.instrumentation.jmx.engine.BeanAttributeExtractor; import io.opentelemetry.instrumentation.jmx.engine.BeanPack; import io.opentelemetry.instrumentation.jmx.engine.MetricAttribute; -import io.opentelemetry.instrumentation.jmx.engine.MetricBanner; import io.opentelemetry.instrumentation.jmx.engine.MetricDef; import io.opentelemetry.instrumentation.jmx.engine.MetricExtractor; +import io.opentelemetry.instrumentation.jmx.engine.MetricInfo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -138,17 +138,17 @@ public MetricDef buildMetricDef() throws Exception { MetricExtractor[] metricExtractors = new MetricExtractor[attrNames.size()]; int n = 0; for (String attributeName : attrNames) { - MetricBanner banner; + MetricInfo metricInfo; Metric m = mapping.get(attributeName); if (m == null) { - banner = - new MetricBanner( + metricInfo = + new MetricInfo( prefix == null ? attributeName : (prefix + attributeName), null, getUnit(), getMetricType()); } else { - banner = m.buildMetricBanner(prefix, attributeName, getUnit(), getMetricType()); + metricInfo = m.buildMetricInfo(prefix, attributeName, getUnit(), getMetricType()); } BeanAttributeExtractor attrExtractor = BeanAttributeExtractor.fromName(attributeName); @@ -170,7 +170,7 @@ public MetricDef buildMetricDef() throws Exception { MetricExtractor metricExtractor = new MetricExtractor( attrExtractor, - banner, + metricInfo, attributeList.toArray(new MetricAttribute[attributeList.size()])); metricExtractors[n++] = metricExtractor; } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java index 9d5966c052f4..96b5abd38751 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/Metric.java @@ -5,7 +5,7 @@ package io.opentelemetry.instrumentation.jmx.yaml; -import io.opentelemetry.instrumentation.jmx.engine.MetricBanner; +import io.opentelemetry.instrumentation.jmx.engine.MetricInfo; /** * A class representing metric definition as a part of YAML metric rule. Objects of this class are @@ -42,8 +42,8 @@ public void setDesc(String desc) { this.desc = desc.trim(); } - MetricBanner buildMetricBanner( - String prefix, String attributeName, String defaultUnit, MetricBanner.Type defaultType) { + MetricInfo buildMetricInfo( + String prefix, String attributeName, String defaultUnit, MetricInfo.Type defaultType) { String metricName; if (metric == null) { metricName = prefix == null ? attributeName : (prefix + attributeName); @@ -51,7 +51,7 @@ MetricBanner buildMetricBanner( metricName = prefix == null ? metric : (prefix + metric); } - MetricBanner.Type metricType = getMetricType(); + MetricInfo.Type metricType = getMetricType(); if (metricType == null) { metricType = defaultType; } @@ -61,6 +61,6 @@ MetricBanner buildMetricBanner( unit = defaultUnit; } - return new MetricBanner(metricName, desc, unit, metricType); + return new MetricInfo(metricName, desc, unit, metricType); } } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java index 026a09a285a9..17fcc382b16c 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/MetricStructure.java @@ -7,7 +7,7 @@ import io.opentelemetry.instrumentation.jmx.engine.MetricAttribute; import io.opentelemetry.instrumentation.jmx.engine.MetricAttributeExtractor; -import io.opentelemetry.instrumentation.jmx.engine.MetricBanner; +import io.opentelemetry.instrumentation.jmx.engine.MetricInfo; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -33,7 +33,7 @@ abstract class MetricStructure { private Map metricAttribute; // unused, for YAML parser only private String unit; - private MetricBanner.Type metricType; + private MetricInfo.Type metricType; private List metricAttributes; public String getType() { @@ -43,7 +43,7 @@ public String getType() { public void setType(String t) { // Do not complain about case variations t = t.trim().toUpperCase(); - this.metricType = MetricBanner.Type.valueOf(t); + this.metricType = MetricInfo.Type.valueOf(t); this.type = t; } @@ -80,7 +80,7 @@ public Map getMetricAttribute() { return metricAttribute; } - public MetricBanner.Type getMetricType() { + public MetricInfo.Type getMetricType() { return metricType; } diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java index f268279d820e..852f7c063b43 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/AttributeExtractorTest.java @@ -18,9 +18,9 @@ class AttributeExtractorTest { // An MBean used for this test - // CHECKSTYLE:OFF + @SuppressWarnings("checkstyle:AbbreviationAsWordInName") public interface Test1MBean { - // CHECKSTYLE:ON + byte getByteAttribute(); short getShortAttribute(); diff --git a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java index c1e8698accec..79794f208f13 100644 --- a/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java +++ b/instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/RuleParserTest.java @@ -85,7 +85,7 @@ void testConf2() throws Exception { Metric m1 = attr.get("ATTRIBUTE1"); assertThat(m1 == null).isFalse(); assertThat("METRIC_NAME1".equals(m1.getMetric())).isTrue(); - assertThat(m1.getMetricType() == MetricBanner.Type.GAUGE).isTrue(); + assertThat(m1.getMetricType() == MetricInfo.Type.GAUGE).isTrue(); assertThat("UNIT1".equals(m1.getUnit())).isTrue(); assertThat(m1.getMetricAttribute() == null).isFalse(); assertThat(m1.getMetricAttribute().size() == 1).isTrue(); @@ -168,19 +168,19 @@ void testConf4() throws Exception { BeanAttributeExtractor a1 = m1.getMetricValueExtractor(); assertThat("A.b".equals(a1.getAttributeName())).isTrue(); assertThat(m1.getAttributes().length == 3).isTrue(); - MetricBanner mb1 = m1.getBanner(); + MetricInfo mb1 = m1.getInfo(); assertThat("PREFIX.METRIC_NAME1".equals(mb1.getMetricName())).isTrue(); assertThat("DESCRIPTION1".equals(mb1.getDescription())).isTrue(); assertThat("UNIT1".equals(mb1.getUnit())).isTrue(); - assertThat(MetricBanner.Type.COUNTER == mb1.getType()).isTrue(); + assertThat(MetricInfo.Type.COUNTER == mb1.getType()).isTrue(); MetricExtractor m3 = metricDef.getMetricExtractors()[2]; BeanAttributeExtractor a3 = m3.getMetricValueExtractor(); assertThat("ATTRIBUTE3".equals(a3.getAttributeName())).isTrue(); - MetricBanner mb3 = m3.getBanner(); + MetricInfo mb3 = m3.getInfo(); assertThat("PREFIX.ATTRIBUTE3".equals(mb3.getMetricName())).isTrue(); // syntax extension - defining a default unit and type - assertThat(MetricBanner.Type.UPDOWNCOUNTER == mb3.getType()).isTrue(); + assertThat(MetricInfo.Type.UPDOWNCOUNTER == mb3.getType()).isTrue(); assertThat("DEFAULT_UNIT".equals(mb3.getUnit())).isTrue(); } @@ -208,9 +208,9 @@ void testConf5() throws Exception { BeanAttributeExtractor a1 = m1.getMetricValueExtractor(); assertThat("ATTRIBUTE".equals(a1.getAttributeName())).isTrue(); assertThat(m1.getAttributes().length == 0).isTrue(); - MetricBanner mb1 = m1.getBanner(); + MetricInfo mb1 = m1.getInfo(); assertThat("ATTRIBUTE".equals(mb1.getMetricName())).isTrue(); - assertThat(MetricBanner.Type.GAUGE == mb1.getType()).isTrue(); + assertThat(MetricInfo.Type.GAUGE == mb1.getType()).isTrue(); assertThat(null == mb1.getUnit()).isTrue(); } @@ -245,7 +245,7 @@ void testConf6() throws Exception { assertThat(m1.getAttributes().length == 1).isTrue(); MetricAttribute l1 = m1.getAttributes()[0]; assertThat("value2".equals(l1.acquireAttributeValue(null, null))).isTrue(); - MetricBanner mb1 = m1.getBanner(); + MetricInfo mb1 = m1.getInfo(); assertThat("ATTRIBUTE".equals(mb1.getMetricName())).isTrue(); } @@ -278,7 +278,7 @@ void testConf7() throws Exception { BeanAttributeExtractor a1 = m1.getMetricValueExtractor(); assertThat("ATTRIBUTE".equals(a1.getAttributeName())).isTrue(); assertThat(m1.getAttributes().length == 2).isTrue(); - MetricBanner mb1 = m1.getBanner(); + MetricInfo mb1 = m1.getInfo(); assertThat("ATTRIBUTE".equals(mb1.getMetricName())).isTrue(); } From c509c8b84f85bce7c618f00306c642a989d3f033 Mon Sep 17 00:00:00 2001 From: Findeisen Date: Tue, 15 Nov 2022 10:29:30 -0800 Subject: [PATCH 20/20] Post-review change: class renaming --- .../instrumentation/jmx/engine/BeanFinder.java | 2 +- .../jmx/engine/{BeanPack.java => BeanGroup.java} | 6 +++--- .../instrumentation/jmx/engine/MetricDef.java | 8 ++++---- .../instrumentation/jmx/yaml/JmxRule.java | 14 ++++++-------- 4 files changed, 14 insertions(+), 16 deletions(-) rename instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/{BeanPack.java => BeanGroup.java} (87%) diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java index 827c32f400bb..fa44f293cc4e 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanFinder.java @@ -75,7 +75,7 @@ private void refreshState() { * @param servers the list of MBeanServers to query */ private void resolveBeans(MetricDef metricDef, List servers) { - BeanPack beans = metricDef.getBeanPack(); + BeanGroup beans = metricDef.getBeanGroup(); for (MBeanServer server : servers) { // The set of all matching ObjectNames recognized by the server diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanGroup.java similarity index 87% rename from instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java rename to instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanGroup.java index 8bef01c07e57..dc4fb3ef5fbb 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanPack.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/BeanGroup.java @@ -13,19 +13,19 @@ * A class describing a set of MBeans which can be used to collect values for a metric. Objects of * this class are immutable. */ -public class BeanPack { +public class BeanGroup { // How to specify the MBean(s) @Nullable private final QueryExp queryExp; private final ObjectName[] namePatterns; /** - * Constructor for BeanPack. + * Constructor for BeanGroup. * * @param queryExp the QueryExp to be used to filter results when looking for MBeans * @param namePatterns an array of ObjectNames used to look for MBeans; usually they will be * patterns. If multiple patterns are provided, they work as logical OR. */ - public BeanPack(@Nullable QueryExp queryExp, ObjectName... namePatterns) { + public BeanGroup(@Nullable QueryExp queryExp, ObjectName... namePatterns) { this.queryExp = queryExp; this.namePatterns = namePatterns; } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java index 4107a80f83e7..875e90b76cf1 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricDef.java @@ -64,14 +64,14 @@ // // MetricDef def = // new MetricDef( -// new BeanPack(null, new ObjectName("java.lang:name=*,type=MemoryPool")), +// new BeanGroup(null, new ObjectName("java.lang:name=*,type=MemoryPool")), // usageUsedExtractor, // usageMaxExtractor); public class MetricDef { // Describes the MBeans to use - private final BeanPack beans; + private final BeanGroup beans; // Describes how to get the metric values and their attributes, and how to report them private final MetricExtractor[] metricExtractors; @@ -84,12 +84,12 @@ public class MetricDef { * MetricExtractor is provided, they should use unique metric names or unique metric * attributes */ - public MetricDef(BeanPack beans, MetricExtractor... metricExtractors) { + public MetricDef(BeanGroup beans, MetricExtractor... metricExtractors) { this.beans = beans; this.metricExtractors = metricExtractors; } - BeanPack getBeanPack() { + BeanGroup getBeanGroup() { return beans; } diff --git a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java index 3d94f490c1a7..0bb394cc05e3 100644 --- a/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java +++ b/instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/JmxRule.java @@ -6,7 +6,7 @@ package io.opentelemetry.instrumentation.jmx.yaml; import io.opentelemetry.instrumentation.jmx.engine.BeanAttributeExtractor; -import io.opentelemetry.instrumentation.jmx.engine.BeanPack; +import io.opentelemetry.instrumentation.jmx.engine.BeanGroup; import io.opentelemetry.instrumentation.jmx.engine.MetricAttribute; import io.opentelemetry.instrumentation.jmx.engine.MetricDef; import io.opentelemetry.instrumentation.jmx.engine.MetricExtractor; @@ -116,16 +116,16 @@ private static Map validateAttributeMapping(Map * @throws an exception if any issues within the rule are detected */ public MetricDef buildMetricDef() throws Exception { - BeanPack pack; + BeanGroup group; if (bean != null) { - pack = new BeanPack(null, new ObjectName(bean)); + group = new BeanGroup(null, new ObjectName(bean)); } else if (beans != null && !beans.isEmpty()) { ObjectName[] objectNames = new ObjectName[beans.size()]; int k = 0; for (String oneBean : beans) { objectNames[k++] = new ObjectName(oneBean); } - pack = new BeanPack(null, objectNames); + group = new BeanGroup(null, objectNames); } else { throw new IllegalStateException("No ObjectName specified"); } @@ -175,7 +175,7 @@ public MetricDef buildMetricDef() throws Exception { metricExtractors[n++] = metricExtractor; } - return new MetricDef(pack, metricExtractors); + return new MetricDef(group, metricExtractors); } private static List combineMetricAttributes( @@ -190,8 +190,6 @@ private static List combineMetricAttributes( set.put(metricAttribute.getAttributeName(), metricAttribute); } - List result = new ArrayList(); - result.addAll(set.values()); - return result; + return new ArrayList(set.values()); } }