diff --git a/newrelic-opentelemetry-agent-extension/README.md b/newrelic-opentelemetry-agent-extension/README.md index e800ca4468..f3451f7f24 100644 --- a/newrelic-opentelemetry-agent-extension/README.md +++ b/newrelic-opentelemetry-agent-extension/README.md @@ -31,12 +31,48 @@ will need to download the New Relic OpenTelemetry Agent extension, which is publ **IMPORTANT**: This package is marked "-alpha". All APIs and behaviors are subject to change. Please use with caution and be sure to check the release notes for changes before upgrading. -Calls to the [Java agent API](https://docs.newrelic.com/docs/apm/agents/java-agent/api-guides/guide-using-java-agent-api/) API will be routed through the +See [OpenTelemetry Java Getting started guide](https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/get-started/opentelemetry-tutorial-java/) +for information on configuring the OpenTelemetry Java agent to export to New Relic. + +## Supported Operations + +Calls to the [Java agent API](https://docs.newrelic.com/docs/apm/agents/java-agent/api-guides/guide-using-java-agent-api/) will be routed through the OpenTelemetry API. Note that many concepts of the New Relic API do not map to an equivalent in the OpenTelemetry API. When an API is called which is not bridged to OpenTelemetry, the extension will log details from logger named `com.newrelic.opentelemetry.OpenTelemetryNewRelic` at `FINER` level (if `FINEST` level is enabled, a stacktrace to the calling code is included). -TODO: add table defining which NewRelic APIs are supported and describe the behavior of each +The following operations are supported: -See [OpenTelemetry Java Getting started guide](https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/get-started/opentelemetry-tutorial-java/) -for information on configuring the OpenTelemetry Java agent to export to New Relic. +* NewRelic Metric APIs for recording custom timeslice metrics. Record to OpenTelemetry dimensional metrics, where the name of the metric is `newrelic.timeslice.value` for `recordMetric`, `recordResponseTimeMetric`, and `newrelic.timeslice.counter.value` for `incrementCounter`. The name of timeslice metric is set to the value of a dimension on metric with key `metricTimesliceName`. + * `NewRelic.recordMetric(String, float)` + * `NewRelic.recordResponseTimeMetric(String, long)` + * `NewRelic.incrementCounter(String)` + * `NewRelic.incrementCounter(String, int)` + * `MetricAggregator.recordMetric(String, float)` + * `MetricAggregator.recordResponseTimeMetric(String, long)` + * `MetricAggregator.incrementCounter(String)` + * `MetricAggregator.incrementCounter(String, int)` +* NewRelic Error APIs for recording errors. Record the error on whatever OpenTelemetry span is currently active (i.e. `Span.current()`) using `recordException`. Sets the active span status to `ERROR`. + * `NewRelic.noticeError(Throwable, Map)` + * `NewRelic.noticeError(Throwable)` + * `NewRelic.noticeError(String, Map)` + * `NewRelic.noticeError(String)` + * `NewRelic.noticeError(Throwable, Map, boolean)` + * `NewRelic.noticeError(Throwable, boolean)` + * `NewRelic.noticeError(String, Map, boolean)` + * `NewRelic.noticeError(String, boolean)` + * `ErrorApi.noticeError(Throwable, Map)` + * `ErrorApi.noticeError(Throwable)` + * `ErrorApi.noticeError(String, Map)` + * `ErrorApi.noticeError(String)` + * `ErrorApi.noticeError(Throwable, Map, boolean)` + * `ErrorApi.noticeError(Throwable, boolean)` + * `ErrorApi.noticeError(String, Map, boolean)` + * `ErrorApi.noticeError(String, boolean)` +* NewRelic TracedMethod APIs for adding custom attributes. Record the custom attributes to whatever OpenTelemetry span is currently active (i.e. `Span.current()`). + * `TracedMethod.addCustomAttribute(String, Number)` + * `TracedMethod.addCustomAttribute(String, Strg)` + * `TracedMethod.addCustomAttribute(String, boolean)` + * `TracedMethod.addCustomAttributes(Map)` +* NewRelic Insights API for recording custom events. Record the event as an OpenTelemetry LogRecord following the [semantic conventions for events](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/events.md). The `event.domain` is set to `newrelic.agent_api`, the `event.name` is set to the name of the custom event. + * `Insights.recordCustomEvent(String, Map)` \ No newline at end of file diff --git a/newrelic-opentelemetry-agent-extension/src/main/java/com/newrelic/opentelemetry/OpenTelemetryInsights.java b/newrelic-opentelemetry-agent-extension/src/main/java/com/newrelic/opentelemetry/OpenTelemetryInsights.java index b94f92b4ed..598814544a 100644 --- a/newrelic-opentelemetry-agent-extension/src/main/java/com/newrelic/opentelemetry/OpenTelemetryInsights.java +++ b/newrelic-opentelemetry-agent-extension/src/main/java/com/newrelic/opentelemetry/OpenTelemetryInsights.java @@ -10,6 +10,7 @@ final class OpenTelemetryInsights implements Insights { + private static final String NEW_RELIC_AGENT_API_DOMAIN = "newrelic.agent_api"; private final io.opentelemetry.api.logs.Logger logger; private OpenTelemetryInsights(OpenTelemetry openTelemetry) { @@ -24,7 +25,7 @@ static OpenTelemetryInsights create(OpenTelemetry openTelemetry) { public void recordCustomEvent(String eventType, Map attributesMap) { Attributes attributes = OpenTelemetryNewRelic.toAttributes(attributesMap) // TODO: is this the right domain? - .put(SemanticAttributes.EVENT_DOMAIN, "newrelic.api") + .put(SemanticAttributes.EVENT_DOMAIN, NEW_RELIC_AGENT_API_DOMAIN) .put(SemanticAttributes.EVENT_NAME, eventType) .build(); // TODO: use event API when stable. For now, its not possible to without taking diff --git a/newrelic-opentelemetry-agent-extension/src/main/java/com/newrelic/opentelemetry/OpenTelemetryNewRelic.java b/newrelic-opentelemetry-agent-extension/src/main/java/com/newrelic/opentelemetry/OpenTelemetryNewRelic.java index bd31ef48f2..d8acb5289f 100644 --- a/newrelic-opentelemetry-agent-extension/src/main/java/com/newrelic/opentelemetry/OpenTelemetryNewRelic.java +++ b/newrelic-opentelemetry-agent-extension/src/main/java/com/newrelic/opentelemetry/OpenTelemetryNewRelic.java @@ -4,6 +4,7 @@ import com.newrelic.api.agent.ErrorGroupCallback; import com.newrelic.api.agent.Request; import com.newrelic.api.agent.Response; +import com.newrelic.api.agent.TransactionNamePriority; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.AttributesBuilder; @@ -86,6 +87,10 @@ public static void noticeError(String message, boolean expected) { getAgent().getErrorApi().noticeError(message, expected); } + public static void setErrorGroupCallback(ErrorGroupCallback errorGroupCallback) { + getAgent().getErrorApi().setErrorGroupCallback(errorGroupCallback); + } + // **************************** Transaction APIs ********************************// public static void addCustomParameter(String key, Number value) { @@ -109,11 +114,11 @@ public static void setUserId(String userId) { } public static void setTransactionName(String category, String name) { - logUnsupportedMethod("NewRelic", "setTransactionName"); + getAgent().getTransaction().setTransactionName(TransactionNamePriority.CUSTOM_LOW, true, category, name); } public static void ignoreTransaction() { - logUnsupportedMethod("NewRelic", "ignoreTransaction"); + getAgent().getTransaction().ignore(); } public static void ignoreApdex() { @@ -174,9 +179,7 @@ public static void setInstanceName(String instanceName) { logUnsupportedMethod("NewRelic", "setInstanceName"); } - public static void setErrorGroupCallback(ErrorGroupCallback errorGroupCallback) { - getAgent().getErrorApi().setErrorGroupCallback(errorGroupCallback); - } + // Internal helpers static void logUnsupportedMethod(String className, String methodName) { // If FINER or FINEST is enabled, indicate that an unsupported method was called. diff --git a/newrelic-opentelemetry-agent-extension/src/test/java/com/newrelic/api/agent/opentelemetry/OpenTelemetryInsightsTest.java b/newrelic-opentelemetry-agent-extension/src/test/java/com/newrelic/api/agent/opentelemetry/OpenTelemetryInsightsTest.java index 46fce49d50..b262e832aa 100644 --- a/newrelic-opentelemetry-agent-extension/src/test/java/com/newrelic/api/agent/opentelemetry/OpenTelemetryInsightsTest.java +++ b/newrelic-opentelemetry-agent-extension/src/test/java/com/newrelic/api/agent/opentelemetry/OpenTelemetryInsightsTest.java @@ -52,7 +52,7 @@ void recordCustomEvent() { assertThat(exporter.getFinishedLogRecordItems()) .satisfiesExactly(logRecordData -> assertThat(logRecordData) .hasAttributesSatisfying( - equalTo(AttributeKey.stringKey("event.domain"), "newrelic.api"), + equalTo(AttributeKey.stringKey("event.domain"), "newrelic.agent_api"), equalTo(AttributeKey.stringKey("event.name"), "eventType"), satisfies(AttributeKey.doubleKey("double_key"), value -> value.isCloseTo(1.1, Offset.offset(0.01))), equalTo(AttributeKey.longKey("long_key"), 1),