Skip to content

Commit

Permalink
Merge branch 'main' of github.com:newrelic/newrelic-java-agent into j…
Browse files Browse the repository at this point in the history
…ava-23
  • Loading branch information
jasonjkeller committed Sep 18, 2024
2 parents 88633d9 + 857433f commit c1274c4
Show file tree
Hide file tree
Showing 110 changed files with 7,349 additions and 79 deletions.
36 changes: 33 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,39 @@ Noteworthy changes to the agent are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Version 8.14.0
## New features and improvements

* The Java agent supports disabling AI Monitoring at the account/organization level [1972](https://github.com/newrelic/newrelic-java-agent/pull/1972)
* HikariCP instrumentation now captures additional metrics [1976](https://github.com/newrelic/newrelic-java-agent/pull/1976)
* Adds new instrumentation module for `kafka-clients-metrics-3.7.0` [2001](https://github.com/newrelic/newrelic-java-agent/pull/2001)
* Adds new instrumentation module for `jedis-5.0.0` [1969](https://github.com/newrelic/newrelic-java-agent/pull/1969)
* Adds new instrumentation module for `vertx-sqlclient-4.4.2` [2004](https://github.com/newrelic/newrelic-java-agent/pull/2004)
* The `newrelic-scala-api` for Scala 3 will now be published to Maven [1995](https://github.com/newrelic/newrelic-java-agent/pull/1995)
* New AWS MQ attributes will be added to spans [1977](https://github.com/newrelic/newrelic-java-agent/pull/1977)
* Clarify Javadoc comments for `@Trace` API [2009](https://github.com/newrelic/newrelic-java-agent/pull/2009)

## Fixes

* Fixes a `netty-reactor` issue that was causing high memory usage [1978](https://github.com/newrelic/newrelic-java-agent/pull/1978)
* Netty instrumentation will start transactions for HTTP/2 requests [1994](https://github.com/newrelic/newrelic-java-agent/pull/1994)

## Deprecations

The following instrumentation modules are deprecated and will be removed in the next major release:

- `aws-wrap-0.7.0`
- `java.completable-future-jdk8`
- `play-2.3`
- `spring-3.0.0`
- `netty-3.4`
- `Struts v1`

## IAST

- CSEC Version bump to 1.4.1 [2010](https://github.com/newrelic/newrelic-java-agent/pull/2010)
- Changelog: https://github.com/newrelic/csec-java-agent/releases/tag/1.4.1

## Version 8.13.0
## New features and improvements

Expand All @@ -28,14 +61,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Add security-related class excludes during normal class transformer creation [1918](https://github.com/newrelic/newrelic-java-agent/pull/1918)
* Add null checks to vertx 4.5.1 instrumentation [1927](https://github.com/newrelic/newrelic-java-agent/pull/1927)



## IAST

* CSEC Version bump to 1.4.0 [1956](https://github.com/newrelic/newrelic-java-agent/pull/1956)
* [Changelog](https://github.com/newrelic/csec-java-agent/releases/tag/1.4.0)


## Deprecations

- The browser footer injection APIs have been deprecated and will be removed in a future agent release. The header injection API now adds both the header and footer scripts. [1679](https://github.com/newrelic/newrelic-java-agent/pull/1679)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import java.util.regex.Pattern;

public class R2dbcOperation {

public static final OperationAndTableName UNKNOWN_OPERATION_AND_TABLE_NAME = new OperationAndTableName("unknown", "unknown");
static final Pattern VALID_METRIC_NAME_MATCHER = Pattern.compile("[a-zA-Z0-9.$_@]+");
static final int PATTERN_SWITCHES = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
static final Pattern COMMENT_PATTERN = Pattern.compile("/\\*.*?\\*/", Pattern.DOTALL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,16 @@ public interface CollectionFactory {
* @param <V> the type of value stored/returned
*/
<K, V> Function<K, V> memorize(Function<K, V> loader, int maxSize);

/**
* Create a time based eviction cache in which an entry's age is determined on a last-access basis.
*
* @param <K> key type
* @param <V> cached type
* @param ageInSeconds how old, in seconds, a cache entry must be to be evicted after last access
* @param initialCapacity the initial capacity of the cache
* @param loader the function to calculate the value for a key, used if the key is not cached
* @return a time based concurrent cache
*/
<K, V> Function<K, V> createAccessTimeBasedCache(long ageInSeconds, int initialCapacity, Function<K, V> loader);
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,12 @@ public <K, V> Function<K, V> memorize(Function<K, V> loader, int maxSize) {
return loader.apply(k1);
});
}

/**
* Note: In this implementation, this method will return the loader function as is.
*/
@Override
public <K, V> Function<K, V> createAccessTimeBasedCache(long ageInSeconds, int initialCapacity, Function<K, V> loader) {
return loader;
}
}
110 changes: 110 additions & 0 deletions dev-tools/live-templates
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<template name="nrAtTrace" value="@com.newrelic.api.agent.Trace" description="@Trace" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="nrAtTraceAsync" value="@com.newrelic.api.agent.Trace(async = true)" description="@Trace(async = true)" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="nrAtTraceDispatcher" value="@com.newrelic.api.agent.Trace(dispatcher = true)" description="@Trace(dispatcher = true)" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="nrAtWeave" value="@com.newrelic.api.agent.weaver.Weave(type = com.newrelic.api.agent.weaver.MatchType.$MATCH_TYPE$, originalName = &quot;$CLASS_NAME$&quot;)" description="@Weave(originalName = &quot;java.my.Class&quot;, type = Match..." toReformat="true" toShortenFQNames="true">
<variable name="MATCH_TYPE" expression="enum(&quot;ExactClass&quot;, &quot;BaseClass&quot;, &quot;Interface&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="CLASS_NAME" expression="concat(currentPackage(), &quot;.&quot;, fileNameWithoutExtension())" defaultValue="" alwaysStopAt="true" />
<context>
<option name="JAVA_DECLARATION" value="true" />
</context>
</template>
<template name="nrCallOriginal" value="com.newrelic.api.agent.weaver.Weaver.callOriginal();" description="Weaver.callOriginal();" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_EXPRESSION" value="true" />
<option name="JAVA_STATEMENT" value="true" />
</context>
</template>
<template name="nrCallOriginalReturn" value="return com.newrelic.api.agent.weaver.Weaver.callOriginal();" description="return Weaver.callOriginal();" toReformat="true" toShortenFQNames="true">
<context>
<option name="JAVA_STATEMENT" value="true" />
</context>
</template>
<template name="nrHttpParams" value="com.newrelic.api.agent.HttpParameters $PARAMS$ = com.newrelic.api.agent.HttpParameters&#10; .library($LIBRARY$)&#10; .uri($URI$)&#10; .procedure($PROC$)&#10; .inboundHeaders($INBOUND_HEADERS$)&#10; .status($STATUS_CODE$, $STATUS_TEXT$)&#10; .build();" description="HttpParams params = HttpParams.library()...build();" toReformat="true" toShortenFQNames="true">
<variable name="PARAMS" expression="suggestVariableName()" defaultValue="" alwaysStopAt="true" />
<variable name="LIBRARY" expression="variableOfType(&quot;java.lang.String&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="URI" expression="variableOfType(&quot;java/net/URI.java&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="PROC" expression="variableOfType(&quot;java.lang.String&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="INBOUND_HEADERS" expression="" defaultValue="" alwaysStopAt="true" />
<variable name="STATUS_CODE" expression="variableOfType(&quot;int&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="STATUS_TEXT" expression="variableOfType(&quot;java.lang.String&quot;)" defaultValue="" alwaysStopAt="true" />
<context>
<option name="JAVA_STATEMENT" value="true" />
</context>
</template>
<template name="nrLog" value="com.newrelic.api.agent.NewRelic.getAgent().getLogger().log(java.util.logging.Level.$LEVEL$, &quot;$MSG$&quot;);" description="NewRelic.getAgent().getLogger().log(Level..." toReformat="true" toShortenFQNames="true">
<variable name="LEVEL" expression="enum(&quot;SEVERE&quot;, &quot;WARNING&quot;, &quot;INFO&quot;, &quot;FINE&quot;, &quot;FINER&quot;, &quot;FINEST&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="MSG" expression="" defaultValue="" alwaysStopAt="true" />
<context>
<option name="JAVA_STATEMENT" value="true" />
</context>
</template>
<template name="nrMessageConsumeParams" value="com.newrelic.api.agent.MessageConsumeParameters $PARAMS$ = com.newrelic.api.agent.MessageConsumeParameters&#10; .library($LIBRARY$, $OTEL_LIBRARY$)&#10; .destinationType($DEST_TYPE$)&#10; .destinationName($DEST_NAME$)&#10; .inboundHeaders($OUTBOUND_HEADERS$)&#10; .cloudRegion($REGION$)&#10; .cloudAccountId($ACCOUNT_ID$)&#10; .build();" description="MessageProducerParams params = MessageProducerParams.builder()..." toReformat="true" toShortenFQNames="true">
<variable name="PARAMS" expression="suggestVariableName()" defaultValue="" alwaysStopAt="true" />
<variable name="LIBRARY" expression="variableOfType(&quot;java.lang.String&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="OTEL_LIBRARY" expression="variableOfType(&quot;java.lang.String&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="DEST_TYPE" expression="enum(&quot;com.newrelic.api.agent.DestinationType.NAMED_QUEUE&quot;,&quot;com.newrelic.api.agent.DestinationType.TEMP_QUEUE&quot;,&quot;com.newrelic.api.agent.DestinationType.NAMED_TOPIC&quot;,&quot;com.newrelic.api.agent.DestinationType.TEMP_TOPIC&quot;,&quot;com.newrelic.api.agent.DestinationType.EXCHANGE&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="DEST_NAME" expression="variableOfType(&quot;java.lang.String&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="OUTBOUND_HEADERS" expression="variableOfType(&quot;com.newrelic.api.agent.OutboundHeaders&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="REGION" expression="variableOfType(&quot;java.lang.String&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="ACCOUNT_ID" expression="variableOfType(&quot;java.lang.String&quot;)" defaultValue="" alwaysStopAt="true" />
<context>
<option name="JAVA_STATEMENT" value="true" />
</context>
</template>
<template name="nrMessageProduceParams" value="com.newrelic.api.agent.MessageProduceParameters $PARAMS$ = com.newrelic.api.agent.MessageProduceParameters&#10; .library($LIBRARY$, $OTEL_LIBRARY$)&#10; .destinationType($DEST_TYPE$)&#10; .destinationName($DEST_NAME$)&#10; .outboundHeaders($OUTBOUND_HEADERS$)&#10; .cloudRegion($REGION$)&#10; .cloudAccountId($ACCOUNT_ID$)&#10; .build();" description="MessageProducerParams params = MessageProducerParams.builder()..." toReformat="true" toShortenFQNames="true">
<variable name="PARAMS" expression="suggestVariableName()" defaultValue="" alwaysStopAt="true" />
<variable name="LIBRARY" expression="variableOfType(&quot;java.lang.String&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="OTEL_LIBRARY" expression="variableOfType(&quot;java.lang.String&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="DEST_TYPE" expression="enum(&quot;com.newrelic.api.agent.DestinationType.NAMED_QUEUE&quot;,&quot;com.newrelic.api.agent.DestinationType.TEMP_QUEUE&quot;,&quot;com.newrelic.api.agent.DestinationType.NAMED_TOPIC&quot;,&quot;com.newrelic.api.agent.DestinationType.TEMP_TOPIC&quot;,&quot;com.newrelic.api.agent.DestinationType.EXCHANGE&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="DEST_NAME" expression="variableOfType(&quot;java.lang.String&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="OUTBOUND_HEADERS" expression="variableOfType(&quot;com.newrelic.api.agent.OutboundHeaders&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="REGION" expression="variableOfType(&quot;java.lang.String&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="ACCOUNT_ID" expression="variableOfType(&quot;java.lang.String&quot;)" defaultValue="" alwaysStopAt="true" />
<context>
<option name="JAVA_STATEMENT" value="true" />
</context>
</template>
<template name="nrReportAsExternal" value="com.newrelic.api.agent.NewRelic.getAgent().getTracedMethod().reportAsExternal($PARAMS$);" description="NewRelic.getAgent().getTracedMethod().reportAsExternal(params);" toReformat="true" toShortenFQNames="true">
<variable name="PARAMS" expression="variableOfType(&quot;com.newrelic.api.agent.ExternalParameters&quot;)" defaultValue="" alwaysStopAt="true" />
<context>
<option name="JAVA_STATEMENT" value="true" />
</context>
</template>
<template name="nrSegment" value="com.newrelic.api.agent.Segment $SEGMENT$ = com.newrelic.api.agent.NewRelic.getAgent().getTransaction().startSegment(&quot;$CATEGORY$&quot;, &quot;$NAME$&quot;);" description="Segment segment = NewRelic.getAgent().getTransaction().startSegment();" toReformat="true" toShortenFQNames="true">
<variable name="SEGMENT" expression="suggestVariableName()" defaultValue="" alwaysStopAt="true" />
<variable name="CATEGORY" expression="enum(&quot;category&quot;)" defaultValue="" alwaysStopAt="true" />
<variable name="NAME" expression="enum(&quot;optional name&quot;)" defaultValue="" alwaysStopAt="true" />
<context>
<option name="JAVA_STATEMENT" value="true" />
</context>
</template>
<template name="nrToken" value="com.newrelic.api.agent.Token $TOKEN$ = com.newrelic.api.agent.NewRelic.getAgent().getTransaction().getToken();" description="Token token = NewRelic.getAgent().getTransaction().getToken();" toReformat="true" toShortenFQNames="true">
<variable name="TOKEN" expression="suggestVariableName()" defaultValue="" alwaysStopAt="true" />
<context>
<option name="JAVA_STATEMENT" value="true" />
</context>
</template>
<template name="nrTracedMethod" value="com.newrelic.api.agent.TracedMethod $TRACER$ = com.newrelic.api.agent.NewRelic.getAgent().getTracedMethod();" description="TracedMethod tracedMethod = NewRelic.getAgent().getTracedMethod();" toReformat="true" toShortenFQNames="true">
<variable name="TRACER" expression="suggestVariableName()" defaultValue="tracer" alwaysStopAt="true" />
<context>
<option name="JAVA_STATEMENT" value="true" />
</context>
</template>
<template name="nrTx" value="com.newrelic.api.agent.Transaction $TRANSACTION$ = com.newrelic.api.agent.NewRelic.getAgent().getTransaction();" description="Transaction transaction = NewRelic.getAgent().getTransaction();" toReformat="true" toShortenFQNames="true">
<variable name="TRANSACTION" expression="enum(&quot;transaction&quot;, &quot;tx&quot;)" defaultValue="" alwaysStopAt="true" />
<context>
<option name="JAVA_STATEMENT" value="true" />
</context>
</template>
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The agent version.
agentVersion=8.14.0
securityAgentVersion=1.4.0
agentVersion=8.15.0
securityAgentVersion=1.4.1

newrelicDebug=false
org.gradle.jvmargs=-Xmx2048m
Expand Down
12 changes: 12 additions & 0 deletions instrumentation/aws-java-sdk-kinesis-1.11.106/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
dependencies {
implementation(project(":agent-bridge"))
implementation("com.amazonaws:aws-java-sdk-kinesis:1.11.106")
}

jar {
manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.aws-java-sdk-kinesis-1.11.106' }
}

verifyInstrumentation {
passesOnly 'com.amazonaws:aws-java-sdk-kinesis:[1.11.106,)'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.agent.instrumentation.awsjavasdk2.services.kinesis;

import com.amazonaws.AmazonWebServiceRequest;
import com.amazonaws.handlers.AsyncHandler_Instrumentation;
import com.newrelic.agent.bridge.AgentBridge;
import com.newrelic.api.agent.CloudParameters;
import com.newrelic.api.agent.NewRelic;
import com.newrelic.api.agent.Token;
import com.newrelic.api.agent.TracedMethod;

import java.util.Map;

public class KinesisUtil {

public static final String PLATFORM = "aws_kinesis_data_streams";
public static final String TRACE_CATEGORY = "Kinesis";

public static final Map<AmazonWebServiceRequest, Token> requestTokenMap = AgentBridge.collectionFactory.createConcurrentWeakKeyedMap();
private KinesisUtil() {}

public static void setTokenForRequest(AmazonWebServiceRequest request) {
if (AgentBridge.getAgent().getTransaction(false) != null) {
if (request != null) {
Token token = NewRelic.getAgent().getTransaction().getToken();
requestTokenMap.put(request, token);
}
}
}

public static void setTraceInformation(String kinesisOperation, AmazonWebServiceRequest request) {
Token token = KinesisUtil.getToken(request);
if (token != null) {
token.linkAndExpire();
}
KinesisUtil.cleanToken(request);
TracedMethod tracedMethod = NewRelic.getAgent().getTransaction().getTracedMethod();
KinesisUtil.setTraceDetails(kinesisOperation, tracedMethod);
}

public static Token getToken(AmazonWebServiceRequest request) {
if (request != null) {
return requestTokenMap.get(request);
}
return null;
}

public static void cleanToken(AmazonWebServiceRequest request) {
if (request != null) {
requestTokenMap.remove(request);
}
}

public static void setTraceDetails(String kinesisOperation, TracedMethod tracedMethod) {
tracedMethod.setMetricName(TRACE_CATEGORY, kinesisOperation);
tracedMethod.reportAsExternal(createCloudParams());
}

public static CloudParameters createCloudParams() {
// Todo: add arn to cloud parameters
return CloudParameters.provider(PLATFORM).build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
*
* * Copyright 2020 New Relic Corporation. All rights reserved.
* * SPDX-License-Identifier: Apache-2.0
*
*/

package com.amazonaws.handlers;

import com.amazonaws.AmazonWebServiceRequest;
import com.newrelic.api.agent.Token;
import com.newrelic.api.agent.Trace;
import com.newrelic.api.agent.weaver.MatchType;
import com.newrelic.api.agent.weaver.NewField;
import com.newrelic.api.agent.weaver.Weave;
import com.newrelic.api.agent.weaver.Weaver;

@Weave(originalName ="com.amazonaws.handlers.AsyncHandler", type = MatchType.Interface)
public class AsyncHandler_Instrumentation<REQUEST extends AmazonWebServiceRequest, RESULT> {

@NewField
public Token token;

@Trace(async = true)
public void onError(Exception exception) {
if (token != null) {
token.linkAndExpire();
token = null;
}
Weaver.callOriginal();
}

@Trace(async = true)
public void onSuccess(REQUEST request, RESULT result) {
if (token != null) {
token.linkAndExpire();
token = null;
}
Weaver.callOriginal();
}
}
Loading

0 comments on commit c1274c4

Please sign in to comment.