-
Notifications
You must be signed in to change notification settings - Fork 143
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #718 from newrelic/logging-initiative
Logging initiative
- Loading branch information
Showing
83 changed files
with
4,919 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
agent-bridge/src/main/java/com/newrelic/agent/bridge/NoOpLogs.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* | ||
* * Copyright 2022 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package com.newrelic.agent.bridge; | ||
|
||
import com.newrelic.api.agent.Logs; | ||
|
||
import java.util.Map; | ||
|
||
class NoOpLogs implements Logs { | ||
static final Logs INSTANCE = new NoOpLogs(); | ||
|
||
private NoOpLogs() { | ||
} | ||
|
||
@Override | ||
public void recordLogEvent(Map<String, ?> attributes) { | ||
} | ||
|
||
} |
26 changes: 26 additions & 0 deletions
26
agent-bridge/src/main/java/com/newrelic/api/agent/Logs.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
* | ||
* * Copyright 2022 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package com.newrelic.api.agent; | ||
|
||
import java.util.Map; | ||
|
||
/** | ||
* Used to send LogEvents to New Relic. Each LogEvent represents a single log line. | ||
*/ | ||
public interface Logs { | ||
|
||
/** | ||
* Sends a LogEvent for the current application. | ||
* | ||
* @param attributes A map of log event data (e.g. log message, log timestamp, log level) | ||
* Each key should be a String and each value should be a String, Number, or Boolean. | ||
* For map values that are not String, Number, or Boolean object types the toString value will be used. | ||
* @since 7.6.0 | ||
*/ | ||
void recordLogEvent(Map<String, ?> attributes); | ||
} |
43 changes: 43 additions & 0 deletions
43
agent-model/src/main/java/com/newrelic/agent/model/LogEvent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* | ||
* * Copyright 2022 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package com.newrelic.agent.model; | ||
|
||
import org.json.simple.JSONObject; | ||
import org.json.simple.JSONStreamAware; | ||
|
||
import java.io.IOException; | ||
import java.io.Writer; | ||
import java.util.Map; | ||
|
||
public class LogEvent extends AnalyticsEvent implements JSONStreamAware { | ||
|
||
public static final String LOG_EVENT_TYPE = "LogEvent"; | ||
|
||
private volatile float mutablePriority; | ||
|
||
public LogEvent(Map<String, Object> attributes, float priority) { | ||
super(LOG_EVENT_TYPE, System.currentTimeMillis(), priority, attributes); | ||
this.mutablePriority = priority; | ||
} | ||
|
||
@Override | ||
public float getPriority() { | ||
return mutablePriority; | ||
} | ||
|
||
public void setPriority(float priority) { | ||
this.mutablePriority = priority; | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Override | ||
public void writeJSONString(Writer out) throws IOException { | ||
JSONObject.writeJSONString(getMutableUserAttributes(), out); | ||
} | ||
|
||
} |
47 changes: 47 additions & 0 deletions
47
agent-model/src/test/java/com/newrelic/agent/model/LogEventTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package com.newrelic.agent.model; | ||
|
||
import org.junit.Test; | ||
|
||
import java.io.IOException; | ||
import java.io.StringWriter; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
import static org.junit.Assert.*; | ||
|
||
public class LogEventTest { | ||
|
||
@Test | ||
public void testConstructor() { | ||
LogEvent logEvent = new LogEvent(Collections.emptyMap(), 0); | ||
|
||
assertEquals(logEvent.getPriority(), 0, 0); | ||
assertNotNull(logEvent.getMutableUserAttributes()); | ||
assertTrue(logEvent.getMutableUserAttributes().isEmpty()); | ||
} | ||
|
||
@Test | ||
public void testPriorityAccessors() { | ||
LogEvent logEvent = new LogEvent(Collections.emptyMap(), 0); | ||
|
||
assertEquals(0, logEvent.getPriority(), 0); | ||
|
||
logEvent.setPriority(1); | ||
|
||
assertEquals(1, logEvent.getPriority(),0); | ||
} | ||
|
||
@Test | ||
public void testJsonString() throws IOException { | ||
Map<String, Object> attributes = new HashMap<>(); | ||
attributes.put("key", "value"); | ||
|
||
LogEvent logEvent = new LogEvent(attributes, 0); | ||
StringWriter writer = new StringWriter(); | ||
|
||
logEvent.writeJSONString(writer); | ||
|
||
assertEquals("{\"key\":\"value\"}", writer.toString()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
139 changes: 139 additions & 0 deletions
139
functional_test/src/test/java/test/newrelic/test/agent/JavaUtilLoggerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package test.newrelic.test.agent; | ||
|
||
import com.newrelic.agent.Transaction; | ||
import com.newrelic.agent.stats.SimpleStatsEngine; | ||
import com.newrelic.agent.stats.TransactionStats; | ||
import com.newrelic.api.agent.Trace; | ||
import org.junit.Assert; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.logging.Level; | ||
import java.util.logging.LogRecord; | ||
import java.util.logging.Logger; | ||
|
||
/** | ||
* Test for com.newrelic.instrumentation.java.logging-jdk8 instrumentation | ||
*/ | ||
public class JavaUtilLoggerTest { | ||
|
||
private static final String CAPTURED = "This log message should be captured"; | ||
private static final String NOT_CAPTURED = "This message should NOT be captured"; | ||
|
||
@Before | ||
public void setup() { | ||
Transaction.clearTransaction(); | ||
} | ||
|
||
@Trace(dispatcher = true) | ||
@Test | ||
public void shouldIncrementEmittedLogsCountersIndependentlyIfLogLevelEnabled() { | ||
// Given | ||
final Logger logger = Logger.getLogger(JavaUtilLoggerTest.class.getName()); | ||
logger.setLevel(Level.INFO); | ||
|
||
// When | ||
logger.finest(NOT_CAPTURED); | ||
logger.finer(NOT_CAPTURED); | ||
logger.fine(NOT_CAPTURED); | ||
logger.config(NOT_CAPTURED); | ||
logger.info(CAPTURED); | ||
logger.info(CAPTURED); | ||
logger.info(CAPTURED); | ||
logger.warning(CAPTURED); | ||
logger.warning(CAPTURED); | ||
logger.warning(CAPTURED); | ||
logger.warning(CAPTURED); | ||
logger.severe(CAPTURED); | ||
|
||
// Then | ||
Map<String, Integer> metrics = getLogMetricsCounts(); | ||
Assert.assertEquals(8, (int) metrics.get("Logging/lines")); | ||
Assert.assertEquals(0, (int) metrics.get("Logging/lines/FINEST")); | ||
Assert.assertEquals(0, (int) metrics.get("Logging/lines/FINER")); | ||
Assert.assertEquals(0, (int) metrics.get("Logging/lines/FINE")); | ||
Assert.assertEquals(0, (int) metrics.get("Logging/lines/CONFIG")); | ||
Assert.assertEquals(3, (int) metrics.get("Logging/lines/INFO")); | ||
Assert.assertEquals(4, (int) metrics.get("Logging/lines/WARNING")); | ||
Assert.assertEquals(1, (int) metrics.get("Logging/lines/SEVERE")); | ||
} | ||
|
||
@Trace(dispatcher = true) | ||
@Test | ||
public void shouldIncrementAllEmittedLogCountersIfLogLevelIsSetToFinest() { | ||
// Given | ||
final Logger logger = Logger.getLogger(JavaUtilLoggerTest.class.getName()); | ||
logger.setLevel(Level.FINEST); | ||
|
||
// When | ||
logger.finest(CAPTURED); | ||
logger.finer(CAPTURED); | ||
logger.fine(CAPTURED); | ||
logger.config(CAPTURED); | ||
logger.info(CAPTURED); | ||
logger.warning(CAPTURED); | ||
logger.severe(CAPTURED); | ||
|
||
// Then | ||
Map<String, Integer> metrics = getLogMetricsCounts(); | ||
Assert.assertEquals(7, (int) metrics.get("Logging/lines")); | ||
Assert.assertEquals(1, (int) metrics.get("Logging/lines/FINEST")); | ||
Assert.assertEquals(1, (int) metrics.get("Logging/lines/FINER")); | ||
Assert.assertEquals(1, (int) metrics.get("Logging/lines/FINE")); | ||
Assert.assertEquals(1, (int) metrics.get("Logging/lines/CONFIG")); | ||
Assert.assertEquals(1, (int) metrics.get("Logging/lines/INFO")); | ||
Assert.assertEquals(1, (int) metrics.get("Logging/lines/WARNING")); | ||
Assert.assertEquals(1, (int) metrics.get("Logging/lines/SEVERE")); | ||
} | ||
|
||
@Trace(dispatcher = true) | ||
@Test | ||
public void shouldIncrementEmittedLogsCountersIndependentlyIfLogLevelEnabledEvenLoggingLogRecordsDirectly() { | ||
// Given | ||
final Logger logger = Logger.getLogger(JavaUtilLoggerTest.class.getName()); | ||
logger.setLevel(Level.INFO); | ||
|
||
// When | ||
logger.log(new LogRecord(Level.FINEST, NOT_CAPTURED)); | ||
logger.log(new LogRecord(Level.FINER, NOT_CAPTURED)); | ||
logger.log(new LogRecord(Level.FINE, NOT_CAPTURED)); | ||
logger.log(new LogRecord(Level.CONFIG, NOT_CAPTURED)); | ||
logger.log(new LogRecord(Level.INFO, CAPTURED)); | ||
logger.log(new LogRecord(Level.INFO, CAPTURED)); | ||
logger.log(new LogRecord(Level.INFO, CAPTURED)); | ||
logger.log(new LogRecord(Level.WARNING, CAPTURED)); | ||
logger.log(new LogRecord(Level.WARNING, CAPTURED)); | ||
logger.log(new LogRecord(Level.WARNING, CAPTURED)); | ||
logger.log(new LogRecord(Level.WARNING, CAPTURED)); | ||
logger.log(new LogRecord(Level.SEVERE, CAPTURED)); | ||
|
||
// Then | ||
Map<String, Integer> metrics = getLogMetricsCounts(); | ||
Assert.assertEquals(8, (int) metrics.get("Logging/lines")); | ||
Assert.assertEquals(0, (int) metrics.get("Logging/lines/FINEST")); | ||
Assert.assertEquals(0, (int) metrics.get("Logging/lines/FINER")); | ||
Assert.assertEquals(0, (int) metrics.get("Logging/lines/FINE")); | ||
Assert.assertEquals(0, (int) metrics.get("Logging/lines/CONFIG")); | ||
Assert.assertEquals(3, (int) metrics.get("Logging/lines/INFO")); | ||
Assert.assertEquals(4, (int) metrics.get("Logging/lines/WARNING")); | ||
Assert.assertEquals(1, (int) metrics.get("Logging/lines/SEVERE")); | ||
} | ||
|
||
private Map<String, Integer> getLogMetricsCounts() { | ||
Transaction transaction = Transaction.getTransaction(); | ||
TransactionStats transactionStats = transaction.getTransactionActivity().getTransactionStats(); | ||
SimpleStatsEngine engine = transactionStats.getUnscopedStats(); | ||
final Map<String, Integer> metrics = new HashMap<>(); | ||
metrics.put("Logging/lines", engine.getStats("Logging/lines").getCallCount()); | ||
metrics.put("Logging/lines/FINEST", engine.getStats("Logging/lines/FINEST").getCallCount()); | ||
metrics.put("Logging/lines/FINER", engine.getStats("Logging/lines/FINER").getCallCount()); | ||
metrics.put("Logging/lines/FINE", engine.getStats("Logging/lines/FINE").getCallCount()); | ||
metrics.put("Logging/lines/CONFIG", engine.getStats("Logging/lines/CONFIG").getCallCount()); | ||
metrics.put("Logging/lines/INFO", engine.getStats("Logging/lines/INFO").getCallCount()); | ||
metrics.put("Logging/lines/WARNING", engine.getStats("Logging/lines/WARNING").getCallCount()); | ||
metrics.put("Logging/lines/SEVERE", engine.getStats("Logging/lines/SEVERE").getCallCount()); | ||
return metrics; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.