diff --git a/instrumentation/oshi/Makefile b/instrumentation/oshi/Makefile new file mode 100644 index 000000000000..9f5d9d17093b --- /dev/null +++ b/instrumentation/oshi/Makefile @@ -0,0 +1,71 @@ +# From where to resolve the containers (e.g. "otel/weaver"). +WEAVER_CONTAINER_REPOSITORY=docker.io +# Versioned, non-qualified references to containers used in this Makefile. +# These are parsed from dependencies.Dockerfile so dependabot will autoupdate +# the versions of docker files we use. +VERSIONED_WEAVER_CONTAINER_NO_REPO=$(shell cat weaver.Dockerfile | awk '$$4=="weaver" {print $$2}') +# Versioned, non-qualified references to containers used in this Makefile. +WEAVER_CONTAINER=$(WEAVER_CONTAINER_REPOSITORY)/$(VERSIONED_WEAVER_CONTAINER_NO_REPO) + +# Next - we want to run docker as our local file user, so generated code is not +# owned by root, and we don't give unnecessary access. +# +# Determine if "docker" is actually podman +DOCKER_VERSION_OUTPUT := $(shell docker --version 2>&1) +DOCKER_IS_PODMAN := $(shell echo $(DOCKER_VERSION_OUTPUT) | grep -c podman) +ifeq ($(DOCKER_IS_PODMAN),0) + DOCKER_COMMAND := docker +else + DOCKER_COMMAND := podman +endif +DOCKER_RUN=$(DOCKER_COMMAND) run +DOCKER_USER=$(shell id -u):$(shell id -g) +DOCKER_USER_IS_HOST_USER_ARG=-u $(DOCKER_USER) +ifeq ($(DOCKER_COMMAND),podman) + # On podman, additional arguments are needed to make "-u" work + # correctly with the host user ID and host group ID. + # + # Error: OCI runtime error: crun: setgroups: Invalid argument + DOCKER_USER_IS_HOST_USER_ARG=--userns=keep-id -u $(DOCKER_USER) +endif + +.PHONY: generate-docs +generate-docs: + mkdir -p docs + $(DOCKER_RUN) --rm \ + $(DOCKER_USER_IS_HOST_USER_ARG) \ + --mount 'type=bind,source=$(PWD)/model,target=/home/weaver/model,readonly' \ + --mount 'type=bind,source=$(PWD)/templates,target=/home/weaver/templates,readonly' \ + --mount 'type=bind,source=$(PWD)/docs,target=/home/weaver/target' \ + ${WEAVER_CONTAINER} registry generate \ + --registry=/home/weaver/model \ + markdown \ + --future \ + /home/weaver/target + +.PHONY: check +check: + $(DOCKER_RUN) --rm \ + $(DOCKER_USER_IS_HOST_USER_ARG) \ + --mount 'type=bind,source=$(PWD)/model,target=/home/weaver/model,readonly' \ + --mount 'type=bind,source=$(PWD)/templates,target=/home/weaver/templates,readonly' \ + --mount 'type=bind,source=$(PWD)/docs,target=/home/weaver/target' \ + ${WEAVER_CONTAINER} registry check \ + --registry=/home/weaver/model + +.PHONY: generate-java +generate-java: + mkdir -p library/src/main/java/io/opentelemetry/oshi + $(DOCKER_RUN) --rm \ + $(DOCKER_USER_IS_HOST_USER_ARG) \ + --mount 'type=bind,source=$(PWD)/model,target=/home/weaver/model,readonly' \ + --mount 'type=bind,source=$(PWD)/templates,target=/home/weaver/templates,readonly' \ + --mount 'type=bind,source=$(PWD)/library/src/main/java/io/opentelemetry/instrumentation/oshi,target=/home/weaver/target' \ + ${WEAVER_CONTAINER} registry generate \ + --registry=/home/weaver/model \ + java \ + --future \ + /home/weaver/target + +.PHONY: generate +generate: generate-docs generate-java diff --git a/instrumentation/oshi/README.md b/instrumentation/oshi/README.md index 165f43d35236..05350ef34439 100644 --- a/instrumentation/oshi/README.md +++ b/instrumentation/oshi/README.md @@ -7,3 +7,18 @@ # Using OSHI with OpenTelemetry Java agent Download oshi-core jar from https://search.maven.org/search?q=g:com.github.oshi%20AND%20a:oshi-core and place it on the class path. OpenTelemetry Java agent uses system class loader to load classes from the oshi-core jar that are used for the metrics. + + +## Development with weaver + +To regenerate the code (run these from within this `oshi` directory): + +```bash +make generate-java +``` + +To regenerate the documentation: + +```bash +make generate-docs +``` diff --git a/instrumentation/oshi/docs/metrics.md b/instrumentation/oshi/docs/metrics.md new file mode 100644 index 000000000000..85a932f73fae --- /dev/null +++ b/instrumentation/oshi/docs/metrics.md @@ -0,0 +1,140 @@ +# Produced Metrics + + +## Metric `system.memory.utilization` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `system.memory.utilization` | Gauge | `1` | System memory utilization | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `system.memory.utilization` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `state` | string | The type of memory being measured. | `used`; `free`; `cached`; `buffered` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `system.memory.usage` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `system.memory.usage` | UpDownCounter | `By` | System memory usage | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `system.memory.usage` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `state` | string | The type of memory being measured. | `used`; `free`; `cached`; `buffered` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `system.network.io` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `system.network.io` | Counter | `By` | System network IO | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `system.network.io` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `device` | string | The name of the network device. | `eth0` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `direction` | string | The direction of the flow of data being measured. | `receive`; `transmit`; `read`; `write` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `system.network.packets` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `system.network.packets` | Counter | `{packets}` | System network packets | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `system.network.packets` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `device` | string | The name of the network device. | `eth0` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `direction` | string | The direction of the flow of data being measured. | `receive`; `transmit`; `read`; `write` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `system.network.errors` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `system.network.errors` | Counter | `{errors}` | System network errors | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `system.network.errors` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `device` | string | The name of the network device. | `eth0` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `direction` | string | The direction of the flow of data being measured. | `receive`; `transmit`; `read`; `write` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `system.disk.io` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `system.disk.io` | Counter | `By` | System disk IO | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `system.disk.io` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `device` | string | The name of the network device. | `eth0` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `direction` | string | The direction of the flow of data being measured. | `receive`; `transmit`; `read`; `write` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `system.disk.operations` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `system.disk.operations` | Counter | `{operations}` | System disk operations | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `system.disk.operations` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `device` | string | The name of the network device. | `eth0` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | +| `direction` | string | The direction of the flow of data being measured. | `receive`; `transmit`; `read`; `write` | `Required` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `runtime.java.memory` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `runtime.java.memory` | UpDownCounter | `By` | Runtime Java memory | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `runtime.java.memory` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `type` | string | The type of memory measurement | `rss`; `vms` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | + + + +## Metric `runtime.java.cpu_time` + +| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `runtime.java.cpu_time` | Gauge | `ms` | Runtime Java CPU time | ![Development](https://img.shields.io/badge/-development-blue) | + + +### `runtime.java.cpu_time` Attributes + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| `type` | string | The type of CPU time measurement | `user`; `system` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | diff --git a/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/CustomAttributes.java b/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/CustomAttributes.java new file mode 100644 index 000000000000..3637d73d60eb --- /dev/null +++ b/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/CustomAttributes.java @@ -0,0 +1,30 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.oshi; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; + +import io.opentelemetry.api.common.AttributeKey; + +// This file is generated using weaver. Do not edit manually. + +/** Attribute definitions generated from a Weaver model. Do not edit manually. */ +public final class CustomAttributes { + + /** The name of the network device. */ + public static final AttributeKey DEVICE = stringKey("device"); + + /** The direction of the flow of data being measured. */ + public static final AttributeKey DIRECTION = stringKey("direction"); + + /** The type of memory being measured. */ + public static final AttributeKey STATE = stringKey("state"); + + /** The type of measurement being taken. */ + public static final AttributeKey TYPE = stringKey("type"); + + private CustomAttributes() {} +} diff --git a/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/Metrics.java b/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/Metrics.java new file mode 100644 index 000000000000..e11385c3cc82 --- /dev/null +++ b/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/Metrics.java @@ -0,0 +1,105 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.oshi; + +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.ObservableDoubleGauge; +import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; +import io.opentelemetry.api.metrics.ObservableLongCounter; +import io.opentelemetry.api.metrics.ObservableLongGauge; +import io.opentelemetry.api.metrics.ObservableLongMeasurement; +import io.opentelemetry.api.metrics.ObservableLongUpDownCounter; +import java.util.function.Consumer; + +// This file is generated using weaver. Do not edit manually. + +/** Metric definitions generated from a Weaver model. Do not edit manually. */ +public final class Metrics { + + public static ObservableDoubleGauge createSystemMemoryUtilization( + Meter meter, Consumer callback) { + return meter + .gaugeBuilder("system.memory.utilization") + .setUnit("1") + .setDescription("System memory utilization") + .buildWithCallback(callback); + } + + public static ObservableLongUpDownCounter createSystemMemoryUsage( + Meter meter, Consumer callback) { + return meter + .upDownCounterBuilder("system.memory.usage") + .setUnit("By") + .setDescription("System memory usage") + .buildWithCallback(callback); + } + + public static ObservableLongCounter createSystemNetworkIo( + Meter meter, Consumer callback) { + return meter + .counterBuilder("system.network.io") + .setUnit("By") + .setDescription("System network IO") + .buildWithCallback(callback); + } + + public static ObservableLongCounter createSystemNetworkPackets( + Meter meter, Consumer callback) { + return meter + .counterBuilder("system.network.packets") + .setUnit("{packets}") + .setDescription("System network packets") + .buildWithCallback(callback); + } + + public static ObservableLongCounter createSystemNetworkErrors( + Meter meter, Consumer callback) { + return meter + .counterBuilder("system.network.errors") + .setUnit("{errors}") + .setDescription("System network errors") + .buildWithCallback(callback); + } + + public static ObservableLongCounter createSystemDiskIo( + Meter meter, Consumer callback) { + return meter + .counterBuilder("system.disk.io") + .setUnit("By") + .setDescription("System disk IO") + .buildWithCallback(callback); + } + + public static ObservableLongCounter createSystemDiskOperations( + Meter meter, Consumer callback) { + return meter + .counterBuilder("system.disk.operations") + .setUnit("{operations}") + .setDescription("System disk operations") + .buildWithCallback(callback); + } + + public static ObservableLongUpDownCounter createRuntimeJavaMemory( + Meter meter, Consumer callback) { + return meter + .upDownCounterBuilder("runtime.java.memory") + .setUnit("By") + .setDescription("Runtime Java memory") + .buildWithCallback(callback); + } + + public static ObservableLongGauge createRuntimeJavaCpuTime( + Meter meter, Consumer callback) { + return meter + .gaugeBuilder("runtime.java.cpu_time") + .ofLongs() + .setUnit("ms") + .setDescription("Runtime Java CPU time") + .buildWithCallback(callback); + } + + private Metrics() {} +} diff --git a/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/ProcessMetrics.java b/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/ProcessMetrics.java index a4f1f79cbe54..e9d70288b579 100644 --- a/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/ProcessMetrics.java +++ b/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/ProcessMetrics.java @@ -6,7 +6,6 @@ package io.opentelemetry.instrumentation.oshi; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.Meter; import java.util.ArrayList; @@ -17,8 +16,6 @@ /** Java Runtime Metrics Utility. */ public class ProcessMetrics { - private static final AttributeKey TYPE_KEY = AttributeKey.stringKey("type"); - private ProcessMetrics() {} /** Register observers for java runtime metrics. */ @@ -28,30 +25,26 @@ public static List registerObservers(OpenTelemetry openTelemetry) OperatingSystem osInfo = systemInfo.getOperatingSystem(); OSProcess processInfo = osInfo.getProcess(osInfo.getProcessId()); List observables = new ArrayList<>(); + observables.add( - meter - .upDownCounterBuilder("runtime.java.memory") - .setDescription("Runtime Java memory") - .setUnit("By") - .buildWithCallback( - r -> { - processInfo.updateAttributes(); - r.record(processInfo.getResidentSetSize(), Attributes.of(TYPE_KEY, "rss")); - r.record(processInfo.getVirtualSize(), Attributes.of(TYPE_KEY, "vms")); - })); + Metrics.createRuntimeJavaMemory( + meter, + r -> { + processInfo.updateAttributes(); + r.record( + processInfo.getResidentSetSize(), Attributes.of(CustomAttributes.TYPE, "rss")); + r.record(processInfo.getVirtualSize(), Attributes.of(CustomAttributes.TYPE, "vms")); + })); observables.add( - meter - .gaugeBuilder("runtime.java.cpu_time") - .setDescription("Runtime Java CPU time") - .setUnit("ms") - .ofLongs() - .buildWithCallback( - r -> { - processInfo.updateAttributes(); - r.record(processInfo.getUserTime(), Attributes.of(TYPE_KEY, "user")); - r.record(processInfo.getKernelTime(), Attributes.of(TYPE_KEY, "system")); - })); + Metrics.createRuntimeJavaCpuTime( + meter, + r -> { + processInfo.updateAttributes(); + r.record(processInfo.getUserTime(), Attributes.of(CustomAttributes.TYPE, "user")); + r.record(processInfo.getKernelTime(), Attributes.of(CustomAttributes.TYPE, "system")); + })); + return observables; } } diff --git a/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/SystemMetrics.java b/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/SystemMetrics.java index 960d6c0bccdc..fefd86eb3ab3 100644 --- a/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/SystemMetrics.java +++ b/instrumentation/oshi/library/src/main/java/io/opentelemetry/instrumentation/oshi/SystemMetrics.java @@ -6,7 +6,6 @@ package io.opentelemetry.instrumentation.oshi; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.Meter; import java.util.ArrayList; @@ -19,13 +18,8 @@ /** System Metrics Utility. */ public class SystemMetrics { - private static final AttributeKey DEVICE_KEY = AttributeKey.stringKey("device"); - private static final AttributeKey DIRECTION_KEY = AttributeKey.stringKey("direction"); - - private static final AttributeKey STATE_KEY = AttributeKey.stringKey("state"); - - private static final Attributes ATTRIBUTES_USED = Attributes.of(STATE_KEY, "used"); - private static final Attributes ATTRIBUTES_FREE = Attributes.of(STATE_KEY, "free"); + private static final Attributes ATTRIBUTES_USED = Attributes.of(CustomAttributes.STATE, "used"); + private static final Attributes ATTRIBUTES_FREE = Attributes.of(CustomAttributes.STATE, "free"); private SystemMetrics() {} @@ -37,113 +31,122 @@ public static List registerObservers(OpenTelemetry openTelemetry) List observables = new ArrayList<>(); observables.add( - meter - .upDownCounterBuilder("system.memory.usage") - .setDescription("System memory usage") - .setUnit("By") - .buildWithCallback( - r -> { - GlobalMemory mem = hal.getMemory(); - r.record(mem.getTotal() - mem.getAvailable(), ATTRIBUTES_USED); - r.record(mem.getAvailable(), ATTRIBUTES_FREE); - })); + Metrics.createSystemMemoryUsage( + meter, + r -> { + GlobalMemory mem = hal.getMemory(); + r.record(mem.getTotal() - mem.getAvailable(), ATTRIBUTES_USED); + r.record(mem.getAvailable(), ATTRIBUTES_FREE); + })); observables.add( - meter - .gaugeBuilder("system.memory.utilization") - .setDescription("System memory utilization") - .setUnit("1") - .buildWithCallback( - r -> { - GlobalMemory mem = hal.getMemory(); - r.record( - ((double) (mem.getTotal() - mem.getAvailable())) / mem.getTotal(), - ATTRIBUTES_USED); - r.record(((double) mem.getAvailable()) / mem.getTotal(), ATTRIBUTES_FREE); - })); + Metrics.createSystemMemoryUtilization( + meter, + r -> { + GlobalMemory mem = hal.getMemory(); + r.record( + ((double) (mem.getTotal() - mem.getAvailable())) / mem.getTotal(), + ATTRIBUTES_USED); + r.record(((double) mem.getAvailable()) / mem.getTotal(), ATTRIBUTES_FREE); + })); observables.add( - meter - .counterBuilder("system.network.io") - .setDescription("System network IO") - .setUnit("By") - .buildWithCallback( - r -> { - for (NetworkIF networkIf : hal.getNetworkIFs()) { - networkIf.updateAttributes(); - long recv = networkIf.getBytesRecv(); - long sent = networkIf.getBytesSent(); - String device = networkIf.getName(); - r.record(recv, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "receive")); - r.record(sent, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "transmit")); - } - })); + Metrics.createSystemNetworkIo( + meter, + r -> { + for (NetworkIF networkIf : hal.getNetworkIFs()) { + networkIf.updateAttributes(); + long recv = networkIf.getBytesRecv(); + long sent = networkIf.getBytesSent(); + String device = networkIf.getName(); + r.record( + recv, + Attributes.of( + CustomAttributes.DEVICE, device, CustomAttributes.DIRECTION, "receive")); + r.record( + sent, + Attributes.of( + CustomAttributes.DEVICE, device, CustomAttributes.DIRECTION, "transmit")); + } + })); observables.add( - meter - .counterBuilder("system.network.packets") - .setDescription("System network packets") - .setUnit("{packets}") - .buildWithCallback( - r -> { - for (NetworkIF networkIf : hal.getNetworkIFs()) { - networkIf.updateAttributes(); - long recv = networkIf.getPacketsRecv(); - long sent = networkIf.getPacketsSent(); - String device = networkIf.getName(); - r.record(recv, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "receive")); - r.record(sent, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "transmit")); - } - })); + Metrics.createSystemNetworkPackets( + meter, + r -> { + for (NetworkIF networkIf : hal.getNetworkIFs()) { + networkIf.updateAttributes(); + long recv = networkIf.getPacketsRecv(); + long sent = networkIf.getPacketsSent(); + String device = networkIf.getName(); + r.record( + recv, + Attributes.of( + CustomAttributes.DEVICE, device, CustomAttributes.DIRECTION, "receive")); + r.record( + sent, + Attributes.of( + CustomAttributes.DEVICE, device, CustomAttributes.DIRECTION, "transmit")); + } + })); observables.add( - meter - .counterBuilder("system.network.errors") - .setDescription("System network errors") - .setUnit("{errors}") - .buildWithCallback( - r -> { - for (NetworkIF networkIf : hal.getNetworkIFs()) { - networkIf.updateAttributes(); - long recv = networkIf.getInErrors(); - long sent = networkIf.getOutErrors(); - String device = networkIf.getName(); - r.record(recv, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "receive")); - r.record(sent, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "transmit")); - } - })); + Metrics.createSystemNetworkErrors( + meter, + r -> { + for (NetworkIF networkIf : hal.getNetworkIFs()) { + networkIf.updateAttributes(); + long recv = networkIf.getInErrors(); + long sent = networkIf.getOutErrors(); + String device = networkIf.getName(); + r.record( + recv, + Attributes.of( + CustomAttributes.DEVICE, device, CustomAttributes.DIRECTION, "receive")); + r.record( + sent, + Attributes.of( + CustomAttributes.DEVICE, device, CustomAttributes.DIRECTION, "transmit")); + } + })); observables.add( - meter - .counterBuilder("system.disk.io") - .setDescription("System disk IO") - .setUnit("By") - .buildWithCallback( - r -> { - for (HWDiskStore diskStore : hal.getDiskStores()) { - long read = diskStore.getReadBytes(); - long write = diskStore.getWriteBytes(); - String device = diskStore.getName(); - r.record(read, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "read")); - r.record(write, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "write")); - } - })); + Metrics.createSystemDiskIo( + meter, + r -> { + for (HWDiskStore diskStore : hal.getDiskStores()) { + long read = diskStore.getReadBytes(); + long write = diskStore.getWriteBytes(); + String device = diskStore.getName(); + r.record( + read, + Attributes.of( + CustomAttributes.DEVICE, device, CustomAttributes.DIRECTION, "read")); + r.record( + write, + Attributes.of( + CustomAttributes.DEVICE, device, CustomAttributes.DIRECTION, "write")); + } + })); observables.add( - meter - .counterBuilder("system.disk.operations") - .setDescription("System disk operations") - .setUnit("{operations}") - .buildWithCallback( - r -> { - for (HWDiskStore diskStore : hal.getDiskStores()) { - long read = diskStore.getReads(); - long write = diskStore.getWrites(); - String device = diskStore.getName(); - r.record(read, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "read")); - r.record(write, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "write")); - } - })); + Metrics.createSystemDiskOperations( + meter, + r -> { + for (HWDiskStore diskStore : hal.getDiskStores()) { + long read = diskStore.getReads(); + long write = diskStore.getWrites(); + String device = diskStore.getName(); + r.record( + read, + Attributes.of( + CustomAttributes.DEVICE, device, CustomAttributes.DIRECTION, "read")); + r.record( + write, + Attributes.of( + CustomAttributes.DEVICE, device, CustomAttributes.DIRECTION, "write")); + } + })); return observables; } diff --git a/instrumentation/oshi/model/attributes.yaml b/instrumentation/oshi/model/attributes.yaml new file mode 100644 index 000000000000..2f301bec86b2 --- /dev/null +++ b/instrumentation/oshi/model/attributes.yaml @@ -0,0 +1,32 @@ +groups: + - id: shared.attributes + type: attribute_group + brief: Attributes used in OSHI metrics. + attributes: + - id: device + type: string + brief: The name of the network device. + stability: development + requirement_level: required + examples: ["eth0"] + + - id: direction + type: string + brief: The direction of the flow of data being measured. + stability: development + requirement_level: required + examples: ["receive", "transmit", "read", "write"] + + - id: state + type: string + brief: The type of memory being measured. + stability: development + requirement_level: required + examples: ["used", "free", "cached", "buffered"] + + - id: type + type: string + brief: The type of measurement being taken. + stability: development + requirement_level: required + examples: ["rss", "vms", "user", "system"] diff --git a/instrumentation/oshi/model/metrics.yaml b/instrumentation/oshi/model/metrics.yaml new file mode 100644 index 000000000000..496ffea4b5e2 --- /dev/null +++ b/instrumentation/oshi/model/metrics.yaml @@ -0,0 +1,105 @@ +groups: + - id: system.memory.utilization + type: metric + metric_name: system.memory.utilization + brief: System memory utilization + stability: development + instrument: gauge + unit: "1" + annotations: + value_type: double + attributes: + - ref: state + + - id: system.memory.usage + type: metric + metric_name: system.memory.usage + brief: System memory usage + stability: development + instrument: updowncounter + unit: "By" + attributes: + - ref: state + + - id: system.network.io + type: metric + metric_name: system.network.io + brief: System network IO + stability: development + instrument: counter + unit: "By" + attributes: + - ref: device + - ref: direction + + - id: system.network.packets + type: metric + metric_name: system.network.packets + brief: System network packets + stability: development + instrument: counter + unit: "{packets}" + attributes: + - ref: device + - ref: direction + + - id: system.network.errors + type: metric + metric_name: system.network.errors + brief: System network errors + stability: development + instrument: counter + unit: "{errors}" + attributes: + - ref: device + - ref: direction + + - id: system.disk.io + type: metric + metric_name: system.disk.io + brief: System disk IO + stability: development + instrument: counter + unit: "By" + attributes: + - ref: device + - ref: direction + + - id: system.disk.operations + type: metric + metric_name: system.disk.operations + brief: System disk operations + stability: development + instrument: counter + unit: "{operations}" + attributes: + - ref: device + - ref: direction + + - id: runtime.java.memory + type: metric + metric_name: runtime.java.memory + brief: Runtime Java memory + stability: development + instrument: updowncounter + unit: "By" + attributes: + - id: type + type: string + brief: The type of memory measurement + stability: development + examples: ["rss", "vms"] + + - id: runtime.java.cpu_time + type: metric + metric_name: runtime.java.cpu_time + brief: Runtime Java CPU time + stability: development + instrument: gauge + unit: "ms" + attributes: + - id: type + type: string + brief: The type of CPU time measurement + stability: development + examples: ["user", "system"] diff --git a/instrumentation/oshi/model/registry_manifest.yaml b/instrumentation/oshi/model/registry_manifest.yaml new file mode 100644 index 000000000000..5ed2a7e6933c --- /dev/null +++ b/instrumentation/oshi/model/registry_manifest.yaml @@ -0,0 +1,4 @@ +name: oshi-metrics +description: OSHI System Metrics Semantic Conventions +semconv_version: v1.34.0 +schema_base_url: https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/oshi diff --git a/instrumentation/oshi/templates/registry/java/CustomAttributes.java.j2 b/instrumentation/oshi/templates/registry/java/CustomAttributes.java.j2 new file mode 100644 index 000000000000..53dd8d04d64a --- /dev/null +++ b/instrumentation/oshi/templates/registry/java/CustomAttributes.java.j2 @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package io.opentelemetry.instrumentation.oshi; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; +import io.opentelemetry.api.common.AttributeKey; + +// This file is generated using weaver. Do not edit manually. + +/** Attribute definitions generated from a Weaver model. Do not edit manually. */ +public final class CustomAttributes { +{% for attr in ctx %} + /** + {{ attr.brief }} */{% if attr.type == 'string' %} + public final static AttributeKey {{ attr.name.upper().split('.')|join('_') }} = stringKey("{{attr.name}}"); + {% elif attr.type == 'int' %} + public final static AttributeKey {{ attr.name.upper().split('.')|join('_') }} = longKey("{{attr.name}}"); + {% else %} + // UNHANDLED TYPE PLEASE FIXME + public final static AttributeKey {{ attr.name.upper().split('.')|join('_') }} = ??key("{{attr.name}}"); + {% endif %} +{% endfor %} + private CustomAttributes(){} +} diff --git a/instrumentation/oshi/templates/registry/java/Metrics.java.j2 b/instrumentation/oshi/templates/registry/java/Metrics.java.j2 new file mode 100644 index 000000000000..6b0d461e1c43 --- /dev/null +++ b/instrumentation/oshi/templates/registry/java/Metrics.java.j2 @@ -0,0 +1,60 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package io.opentelemetry.instrumentation.oshi; + +import io.opentelemetry.api.metrics.ObservableLongCounter; +import io.opentelemetry.api.metrics.ObservableLongGauge; +import io.opentelemetry.api.metrics.ObservableDoubleGauge; +import io.opentelemetry.api.metrics.ObservableLongUpDownCounter; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.ObservableLongMeasurement; +import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; +import java.util.function.Consumer; + +// This file is generated using weaver. Do not edit manually. + +/** Metric definitions generated from a Weaver model. Do not edit manually. */ +public final class Metrics { +{%- for metric in ctx %} + {%- set isDouble = metric.annotations and metric.annotations.value_type == "double" %} + {%- if metric.instrument == "gauge" %} + + public static {% if isDouble %}ObservableDoubleGauge{% else %}ObservableLongGauge{% endif %} create{{ metric.metric_name.split('.')|map('split', '_')|map('map', 'capitalize')|map('join','')|join }}( + Meter meter, + Consumer<{% if isDouble %}ObservableDoubleMeasurement{% else %}ObservableLongMeasurement{% endif %}> callback) { + return meter + .gaugeBuilder("{{ metric.metric_name }}") + {%- if not isDouble %}.ofLongs(){% endif %} + .setUnit("{{ metric.unit }}") + .setDescription("{{ metric.brief }}") + .buildWithCallback(callback); + } + {%- elif metric.instrument == "counter" %} + + public static ObservableLongCounter create{{ metric.metric_name.split('.')|map('split', '_')|map('map', 'capitalize')|map('join','')|join }}( + Meter meter, + Consumer callback) { + return meter + .counterBuilder("{{ metric.metric_name }}") + .setUnit("{{ metric.unit }}") + .setDescription("{{ metric.brief }}") + .buildWithCallback(callback); + } + {%- elif metric.instrument == "updowncounter" %} + + public static ObservableLongUpDownCounter create{{ metric.metric_name.split('.')|map('split', '_')|map('map', 'capitalize')|map('join','')|join }}( + Meter meter, + Consumer callback) { + return meter + .upDownCounterBuilder("{{ metric.metric_name }}") + .setUnit("{{ metric.unit }}") + .setDescription("{{ metric.brief }}") + .buildWithCallback(callback); + } + {%- endif %} +{%- endfor %} + + private Metrics(){} +} diff --git a/instrumentation/oshi/templates/registry/java/weaver.yaml b/instrumentation/oshi/templates/registry/java/weaver.yaml new file mode 100644 index 000000000000..9da29d3e27ec --- /dev/null +++ b/instrumentation/oshi/templates/registry/java/weaver.yaml @@ -0,0 +1,7 @@ +templates: + - template: Metrics.java.j2 + filter: '.groups | map(select(.type == "metric"))' + application_mode: single + - template: CustomAttributes.java.j2 + filter: '.groups | map(select(.type == "attribute_group")) | map(.attributes[])' + application_mode: single diff --git a/instrumentation/oshi/templates/registry/markdown/attribute_macros.j2 b/instrumentation/oshi/templates/registry/markdown/attribute_macros.j2 new file mode 100644 index 000000000000..9c0fea34e9ff --- /dev/null +++ b/instrumentation/oshi/templates/registry/markdown/attribute_macros.j2 @@ -0,0 +1,36 @@ +{% import 'examples_macros.j2' as examples %} +{% macro type(attribute) %}{%- if attribute.type is mapping %} +{%- if attribute.type.members[0].value is string %}string{%- endif %} +{%- if attribute.type.members[0].value is int %}int{%- endif %} +{%- if attribute.type.members[0].value is float %}double{%- endif %} +{%- elif attribute.type == "template[boolean]" %}boolean +{%- elif attribute.type == "template[int]" %}int +{%- elif attribute.type == "template[double]" %}double +{%- elif attribute.type == "template[string]" %}string +{%- elif attribute.type == "template[boolean[]]" %}boolean[] +{%- elif attribute.type == "template[int[]]" %}int[] +{%- elif attribute.type == "template[double[]]" %}double[] +{%- elif attribute.type == "template[string[]]" %}string[] +{%- else %}{{ attribute.type | trim }}{%- endif %}{% endmacro %} + +{% macro name(attribute) %}{%- if attribute.type is startingwith("template[") %}`{{ attribute.name }}.` +{%- else %}`{{ attribute.name }}`{%- endif %}{% endmacro %} + +{% macro find_lineage(attr_id, lineage) %}{% if attr_id in lineage %}{{lineage[attr_id].source_group}}{% endif %}{% endmacro %} + +{% macro name_with_link(attribute, attribute_registry_base_url, lineage_attributes) %}[{{name(attribute)}}]({{attribute_registry_base_url}}/{{ find_lineage(attribute.name, lineage_attributes) | split_id | list | reject("eq", "registry")| first | kebab_case }}.md){% endmacro %} + +{% macro display_name(group) %} +{%- if 'display_name' in group %}{{ group.display_name }} +{%- else %}{{ group.id | split_id | list | reject("eq", "registry") | join(" ") | title_case | acronym }} Attributes +{%- endif %}{% endmacro %} + +{% macro heading_link_fragments(title) %}{{ title | trim | lower | replace(" ", "-") | replace("(", "") | replace(")", "") | replace("/", "") | replace("\\", "") | replace(".", "") | replace("!", "") | replace("?", "") | replace("~", "") | replace("#", "")}}{% endmacro %} + +{% macro humanize(text) %} + {{- text.replace('_', ' ') -}} +{% endmacro %} + +{% macro sentence_case(text) %} + {{- text[:1].upper() + text[1:].lower() -}} +{% endmacro %} diff --git a/instrumentation/oshi/templates/registry/markdown/attribute_table.j2 b/instrumentation/oshi/templates/registry/markdown/attribute_table.j2 new file mode 100644 index 000000000000..b40c547887fd --- /dev/null +++ b/instrumentation/oshi/templates/registry/markdown/attribute_table.j2 @@ -0,0 +1,13 @@ +{% import 'requirement.j2' as requirement %} +{% import 'stability.j2' as stability %} +{% import 'notes.j2' as notes %} +{% import 'attribute_macros.j2' as attrs %} +{% import 'enum_macros.j2' as enums %} +{% import 'sampling_macros.j2' as sampling %} +{% import 'examples_macros.j2' as examples %} +{#- Macro for creating attribute table -#} +{% macro generate(attributes, tag_filter, attribute_registry_base_url, lineage_attributes) %}{% if (tag_filter | length == 0) %}{% set filtered_attributes = attributes %}{% else %}{% set filtered_attributes = attributes | selectattr("tag", "in", tag_filter) %}{% endif %}{% if filtered_attributes | length > 0 %}| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +{% for attribute in filtered_attributes | attribute_sort %}| {{ attrs.name(attribute) }} | {{ attrs.type(attribute) }} | {{ attribute.brief | trim }}{{ notes.add({"note": attribute.note, "name": attribute.name}) }} | {{ examples.format(attribute) | trim }} | {{ requirement.render({"level": attribute.requirement_level, "name": attribute.name}, notes) | trim }} | {{ stability.badge(attribute.stability, attribute.deprecated) | trim }} | +{% endfor %}{{ notes.render() }}{{ sampling.snippet(filtered_attributes, attribute_registry_base_url, lineage_attributes) }}{{ enums.tables(filtered_attributes | selectattr("type", "mapping"), notes) }} +{% endif %}{% endmacro %} diff --git a/instrumentation/oshi/templates/registry/markdown/enum_macros.j2 b/instrumentation/oshi/templates/registry/markdown/enum_macros.j2 new file mode 100644 index 000000000000..c8bd6e0eb248 --- /dev/null +++ b/instrumentation/oshi/templates/registry/markdown/enum_macros.j2 @@ -0,0 +1,30 @@ +{% import 'stability.j2' as stability %} +{% macro filter(member) %}{% if (member.deprecated is none or member.deprecated == "") %}{{ "True" }}{% else %}{{ "False" }}{% endif %}{% endmacro %} +{% macro table(enum, notes) %} +--- + +`{{enum.name}}` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +|---|---|---| +{% for espec in enum.type.members | sort(attribute='value') %} +{%- if filter(espec) == "True" -%} +| `{{ espec.value }}` | {{ (espec.brief or espec.id) | trim }}{{ notes.add({"note": espec.note}) }} | {{ stability.badge(espec.stability, espec.deprecated) }} | +{% endif %}{% endfor %}{{ notes.render() }}{% endmacro %} +{% macro tables(enums, notes) -%} +{% for enum in enums | sort(attribute="name") -%} +{{ table(enum, notes) -}} +{% endfor %}{% endmacro %} +{% macro field_table(enum, notes) %} +`{{enum.id}}` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. + +| Value | Description | Stability | +|---|---|---| +{% for espec in enum.members | sort(attribute='value') %} +{%- if filter(espec) == "True" -%} +| `{{ espec.value }}` | {{ (espec.brief or espec.id) | trim }}{{ notes.add({"note": espec.note}) }} | {{ stability.badge(espec.stability, espec.deprecated) }} | +{% endif %}{% endfor %}{{ notes.render() }}{% endmacro %} +{% macro field_tables(enums, notes) -%} +{% for enum in enums | sort(attribute="id") -%} +{{ field_table(enum, notes) -}} +{% endfor %}{% endmacro %} diff --git a/instrumentation/oshi/templates/registry/markdown/examples_macros.j2 b/instrumentation/oshi/templates/registry/markdown/examples_macros.j2 new file mode 100644 index 000000000000..bbd840d67fe5 --- /dev/null +++ b/instrumentation/oshi/templates/registry/markdown/examples_macros.j2 @@ -0,0 +1,17 @@ +{% macro print_examples(examples) %}{%- for e in examples %}{%if loop.first == false %}; {% endif %}`{{ e | trim }}`{%- endfor %}{% endmacro %} + +{% macro format(item) %}{%- if item.examples %} +{%- if "[]" in item.type and "template" not in item.type %} +{%- if item.examples is sequence %} +{%- if item.examples | select("sequence") | length == 0 %}`{{ item.examples | trim }}` +{%- else %}{{ print_examples(item.examples) }} +{%- endif %} +{%- else %}`[{{ item.examples | trim }}]` +{%- endif %} +{%- elif item.examples is sequence %}{{ print_examples(item.examples) }} +{%- else %}`{{ item.examples | trim }}` +{%- endif %}{%- elif item.type is mapping %} +{%- for e in item.type.members %}{% if loop.index0 < 3 %}{% if loop.first == false %}; {% endif %}`{{ e.value | trim }}`{% endif %}{%- endfor %} +{%- elif item.type == "enum" -%} +{%- for e in item.members %}{% if loop.index0 < 3 %}{% if loop.first == false %}; {% endif %}`{{ e.value | trim }}`{% endif %}{%- endfor %} +{%- endif %}{% endmacro %} diff --git a/instrumentation/oshi/templates/registry/markdown/metric_macros.j2 b/instrumentation/oshi/templates/registry/markdown/metric_macros.j2 new file mode 100644 index 000000000000..deae008dd8bb --- /dev/null +++ b/instrumentation/oshi/templates/registry/markdown/metric_macros.j2 @@ -0,0 +1,8 @@ +{% macro instrument(type) -%} +{%- if type == "gauge" %}Gauge +{% elif type == "counter" %}Counter +{% elif type == "updowncounter" %}UpDownCounter +{% elif type == "histogram" %}Histogram +{% else %}{{ type }} +{%- endif %} +{% endmacro %} diff --git a/instrumentation/oshi/templates/registry/markdown/metric_table.j2 b/instrumentation/oshi/templates/registry/markdown/metric_table.j2 new file mode 100644 index 000000000000..ddbd191c6d47 --- /dev/null +++ b/instrumentation/oshi/templates/registry/markdown/metric_table.j2 @@ -0,0 +1,7 @@ +{% import 'stability.j2' as stability %} +{% import 'notes.j2' as notes %} +{% import 'metric_macros.j2' as metrics %} +{% macro generate(group) %}| Name | Instrument Type | Unit (UCUM) | Description | Stability | +| -------- | --------------- | ----------- | -------------- | --------- | +| `{{ group.metric_name }}` | {{ metrics.instrument(group.instrument) | trim }} | `{{ group.unit }}` | {{ group.brief | trim }}{{ notes.add({"note": group.note}) }} | {{ stability.badge(group.stability, group.deprecated) | trim }} | +{{ notes.render() }}{% endmacro %} diff --git a/instrumentation/oshi/templates/registry/markdown/metrics.md.j2 b/instrumentation/oshi/templates/registry/markdown/metrics.md.j2 new file mode 100644 index 000000000000..2f9b885cff6d --- /dev/null +++ b/instrumentation/oshi/templates/registry/markdown/metrics.md.j2 @@ -0,0 +1,14 @@ +{%- import 'attribute_table.j2' as at -%} +{%- import 'metric_table.j2' as mt -%} + +# Produced Metrics + +{% for metric in ctx %} +## Metric `{{metric.metric_name}}` + +{{ mt.generate(metric) }} + +### `{{metric.metric_name}}` Attributes + +{{ at.generate(metric.attributes, "", "", metric.lineage.attributes) }} +{% endfor %} diff --git a/instrumentation/oshi/templates/registry/markdown/notes.j2 b/instrumentation/oshi/templates/registry/markdown/notes.j2 new file mode 100644 index 000000000000..a96b4270e80d --- /dev/null +++ b/instrumentation/oshi/templates/registry/markdown/notes.j2 @@ -0,0 +1,9 @@ +{%- set ns = namespace(notes=[],index=0) -%} +{%- macro add(note) %}{% if note.note %}{% set ns.notes = [ns.notes, [note]] | flatten %} [{{ ns.notes | length + ns.index }}]{% endif %}{% endmacro %} +{%- macro add_with_limit(note) %}{% if note.note | length > 50 %}{% set ns.notes = [ns.notes, [note]] | flatten %} [{{ ns.notes | length + ns.index }}]{% elif note.note %} {{ note.note | trim }}{% endif %}{% endmacro %} +{% macro render() %}{% if ns.notes | length > 0 %} +{%- for note in ns.notes %} +{% if note.name %}**[{{ns.index+loop.index}}] `{{note.name}}`:** {{ note.note | trim }}{% else -%}**[{{ns.index+loop.index}}]:** {{ note.note | trim }} {%- endif -%} +{%- if not loop.last -%}{{"\n"}}{%- endif -%} +{% endfor %}{% set ns.index = ns.notes | length + ns.index %}{% set ns.notes = [] %} +{% endif %}{% endmacro %} diff --git a/instrumentation/oshi/templates/registry/markdown/requirement.j2 b/instrumentation/oshi/templates/registry/markdown/requirement.j2 new file mode 100644 index 000000000000..1f5714de3303 --- /dev/null +++ b/instrumentation/oshi/templates/registry/markdown/requirement.j2 @@ -0,0 +1,9 @@ +{% macro render(attr, notes) -%} +{%- if attr.level == "recommended" %}`Recommended` +{% elif attr.level == "required" %}`Required` +{% elif attr.level == "opt_in" %}`Opt-In` +{% elif attr.level.conditionally_required %}`Conditionally Required`{{ notes.add_with_limit({"note": attr.level.conditionally_required, "name": attr.name}) }} +{% elif attr.level.recommended %}`Recommended`{{ notes.add_with_limit({"note": attr.level.recommended, "name": attr.name}) }} +{% else %}{{ level }} +{%- endif %} +{% endmacro %} diff --git a/instrumentation/oshi/templates/registry/markdown/sampling_macros.j2 b/instrumentation/oshi/templates/registry/markdown/sampling_macros.j2 new file mode 100644 index 000000000000..07929e7d41c9 --- /dev/null +++ b/instrumentation/oshi/templates/registry/markdown/sampling_macros.j2 @@ -0,0 +1,7 @@ +{% import 'attribute_macros.j2' as attrs %} +{% macro snippet(attributes, attribute_registry_base_url, lineage_attributes) %}{% set sampling_attributes = attributes | selectattr("sampling_relevant", "true") %}{% if sampling_attributes | length > 0 %} +The following attributes can be important for making sampling decisions +and SHOULD be provided **at span creation time** (if provided at all): + +{% for attribute in sampling_attributes | sort(attribute="name") %}* {{ attrs.name_with_link(attribute, attribute_registry_base_url, lineage_attributes) }} +{% endfor %}{% endif %}{% endmacro %} diff --git a/instrumentation/oshi/templates/registry/markdown/stability.j2 b/instrumentation/oshi/templates/registry/markdown/stability.j2 new file mode 100644 index 000000000000..cc9ed7bde6d0 --- /dev/null +++ b/instrumentation/oshi/templates/registry/markdown/stability.j2 @@ -0,0 +1,11 @@ +{% macro badge(stability, deprecated) -%} +{%- if deprecated %}![Deprecated](https://img.shields.io/badge/-deprecated-red)
{{ deprecated.note | trim }} +{%- elif stability == "mixed" %}![Mixed](https://img.shields.io/badge/-mixed-yellow) +{%- elif stability == "stable" %}![Stable](https://img.shields.io/badge/-stable-lightgreen) +{%- elif stability == "release_candidate" %}![Release Candidate](https://img.shields.io/badge/-rc-mediumorchid) +{%- elif stability == "deprecated" %}![Deprecated](https://img.shields.io/badge/-deprecated-red) +{%- elif stability == "experimental" %}![Development](https://img.shields.io/badge/-development-blue) +{%- elif stability == "development" %}![Development](https://img.shields.io/badge/-development-blue) +{%- else %}{{ "Unknown stability." }} +{%- endif %} +{%- endmacro %} diff --git a/instrumentation/oshi/templates/registry/markdown/weaver.yaml b/instrumentation/oshi/templates/registry/markdown/weaver.yaml new file mode 100644 index 000000000000..8e015d60cd02 --- /dev/null +++ b/instrumentation/oshi/templates/registry/markdown/weaver.yaml @@ -0,0 +1,4 @@ +templates: + - pattern: metrics.md.j2 + filter: '.groups | map(select(.type == "metric"))' + application_mode: single diff --git a/instrumentation/oshi/weaver.Dockerfile b/instrumentation/oshi/weaver.Dockerfile new file mode 100644 index 000000000000..ffa73b4266fb --- /dev/null +++ b/instrumentation/oshi/weaver.Dockerfile @@ -0,0 +1,6 @@ +# DO NOT BUILD +# This file is just for tracking dependencies of the semantic convention build. +# Dependabot can keep this file up to date with latest containers. + +# Weaver is used to generate markdown docs, and enforce policies on the model and run integration tests. +FROM otel/weaver:v0.16.1 AS weaver