Skip to content

Commit

Permalink
feature/mdc-in-log-forwarding: Include MDC data into logs forwarded t…
Browse files Browse the repository at this point in the history
…o NR from log4j-2 and logback
  • Loading branch information
StanlieK committed Jun 3, 2022
1 parent 4e5074c commit e2aacd6
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.util.ReadOnlyStringMap;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
Expand All @@ -34,11 +35,14 @@ public class AgentUtil {
private static final String ENTITY_GUID = "entity.guid";
private static final String ENTITY_NAME = "entity.name";
private static final String SPAN_ID = "span.id";
// Log attribute prefixes
private static final String MDC_ATTRIBUTE_PREFIX = "mdc.";
// Enabled defaults
private static final boolean APP_LOGGING_DEFAULT_ENABLED = true;
private static final boolean APP_LOGGING_METRICS_DEFAULT_ENABLED = true;
private static final boolean APP_LOGGING_FORWARDING_DEFAULT_ENABLED = true;
private static final boolean APP_LOGGING_LOCAL_DECORATING_DEFAULT_ENABLED = false;
private static final boolean APP_LOGGING_FORWARDING_INCLUDE_MDC_DEFAULT_ENABLED = false;

/**
* Record a LogEvent to be sent to New Relic.
Expand All @@ -52,11 +56,15 @@ public static void recordNewRelicLogEvent(LogEvent event) {
String formattedMessage = message.getFormattedMessage();
// Bail out and don't create a LogEvent if log message is empty
if (formattedMessage != null && !formattedMessage.isEmpty()) {
HashMap<String, Object> logEventMap = new HashMap<>(DEFAULT_NUM_OF_LOG_EVENT_ATTRIBUTES);
HashMap<String, Object> logEventMap = new HashMap<>(getDefaultNumOfLogEventAttributes(event.getContextData()));

logEventMap.put(MESSAGE, formattedMessage);
logEventMap.put(TIMESTAMP, event.getTimeMillis());

if (isApplicationLoggingForwardingIncludeMdcEnabled() && event.getContextData() != null) {
event.getContextData().forEach((key, value) -> logEventMap.put(MDC_ATTRIBUTE_PREFIX + key, value));
}

Level level = event.getLevel();
if (level != null) {
String levelName = level.name();
Expand All @@ -73,6 +81,12 @@ public static void recordNewRelicLogEvent(LogEvent event) {
}
}

private static int getDefaultNumOfLogEventAttributes(ReadOnlyStringMap mdcPropertyMap) {
return isApplicationLoggingForwardingIncludeMdcEnabled() && mdcPropertyMap != null
? mdcPropertyMap.size() + DEFAULT_NUM_OF_LOG_EVENT_ATTRIBUTES
: DEFAULT_NUM_OF_LOG_EVENT_ATTRIBUTES;
}

/**
* Gets a String representing the agent linking metadata in blob format:
* NR-LINKING|entity.guid|hostname|trace.id|span.id|entity.name|
Expand Down Expand Up @@ -153,4 +167,13 @@ public static boolean isApplicationLoggingForwardingEnabled() {
public static boolean isApplicationLoggingLocalDecoratingEnabled() {
return NewRelic.getAgent().getConfig().getValue("application_logging.local_decorating.enabled", APP_LOGGING_LOCAL_DECORATING_DEFAULT_ENABLED);
}

/**
* Check if the application_logging forwarding include_mdc feature is enabled.
*
* @return true if enabled, else false
*/
public static boolean isApplicationLoggingForwardingIncludeMdcEnabled() {
return NewRelic.getAgent().getConfig().getValue("application_logging.forwarding.include_mdc.enabled", APP_LOGGING_FORWARDING_INCLUDE_MDC_DEFAULT_ENABLED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import static com.nr.agent.instrumentation.logbackclassic12.AgentUtil.isApplicationLoggingLocalDecoratingEnabled;
import static com.nr.agent.instrumentation.logbackclassic12.AgentUtil.recordNewRelicLogEvent;

import java.util.Map;

@Weave(originalName = "ch.qos.logback.classic.spi.LoggingEvent", type = MatchType.ExactClass)
public class LoggingEvent_Instrumentation {

Expand Down Expand Up @@ -67,7 +69,7 @@ public LoggingEvent_Instrumentation(String fqcn, Logger logger, Level level, Str

if (applicationLoggingEnabled && isApplicationLoggingForwardingEnabled()) {
// Record and send LogEvent to New Relic
recordNewRelicLogEvent(getFormattedMessage(), timeStamp, level);
recordNewRelicLogEvent(getFormattedMessage(), getMdc(), timeStamp, level);
}
}

Expand All @@ -79,4 +81,8 @@ private Throwable extractThrowableAnRearrangeArguments(Object[] argArray) {
return Weaver.callOriginal();
}

public Map<String, String> getMdc() {
return Weaver.callOriginal();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,14 @@ public class AgentUtil {
private static final String ENTITY_GUID = "entity.guid";
private static final String ENTITY_NAME = "entity.name";
private static final String SPAN_ID = "span.id";
// Log attribute prefixes
private static final String MDC_ATTRIBUTE_PREFIX = "mdc.";
// Enabled defaults
private static final boolean APP_LOGGING_DEFAULT_ENABLED = true;
private static final boolean APP_LOGGING_METRICS_DEFAULT_ENABLED = true;
private static final boolean APP_LOGGING_FORWARDING_DEFAULT_ENABLED = true;
private static final boolean APP_LOGGING_LOCAL_DECORATING_DEFAULT_ENABLED = false;
private static final boolean APP_LOGGING_FORWARDING_INCLUDE_MDC_DEFAULT_ENABLED = false;

/**
* Record a LogEvent to be sent to New Relic.
Expand All @@ -45,10 +48,10 @@ public class AgentUtil {
* @param timeStampMillis log timestamp
* @param level log level
*/
public static void recordNewRelicLogEvent(String message, long timeStampMillis, Level level) {
public static void recordNewRelicLogEvent(String message, Map<String, String> mdcPropertyMap, long timeStampMillis, Level level) {
// Bail out and don't create a LogEvent if log message is empty
if (!message.isEmpty()) {
HashMap<String, Object> logEventMap = new HashMap<>(DEFAULT_NUM_OF_LOG_EVENT_ATTRIBUTES);
HashMap<String, Object> logEventMap = new HashMap<>(getDefaultNumOfLogEventAttributes(mdcPropertyMap));
logEventMap.put(MESSAGE, message);
logEventMap.put(TIMESTAMP, timeStampMillis);

Expand All @@ -58,10 +61,20 @@ public static void recordNewRelicLogEvent(String message, long timeStampMillis,
logEventMap.put(LEVEL, level);
}

if (isApplicationLoggingForwardingIncludeMdcEnabled()) {
mdcPropertyMap.forEach((key, value) -> logEventMap.put(MDC_ATTRIBUTE_PREFIX + key, value));
}

AgentBridge.getAgent().getLogSender().recordLogEvent(logEventMap);
}
}

private static int getDefaultNumOfLogEventAttributes(Map<String, String> mdcPropertyMap) {
return isApplicationLoggingForwardingIncludeMdcEnabled()
? mdcPropertyMap.size() + DEFAULT_NUM_OF_LOG_EVENT_ATTRIBUTES
: DEFAULT_NUM_OF_LOG_EVENT_ATTRIBUTES;
}

/**
* Gets a String representing the agent linking metadata in blob format:
* NR-LINKING|entity.guid|hostname|trace.id|span.id|entity.name|
Expand Down Expand Up @@ -142,4 +155,13 @@ public static boolean isApplicationLoggingForwardingEnabled() {
public static boolean isApplicationLoggingLocalDecoratingEnabled() {
return NewRelic.getAgent().getConfig().getValue("application_logging.local_decorating.enabled", APP_LOGGING_LOCAL_DECORATING_DEFAULT_ENABLED);
}

/**
* Check if the application_logging forwarding include_mdc feature is enabled.
*
* @return true if enabled, else false
*/
public static boolean isApplicationLoggingForwardingIncludeMdcEnabled() {
return NewRelic.getAgent().getConfig().getValue("application_logging.forwarding.include_mdc.enabled", APP_LOGGING_FORWARDING_INCLUDE_MDC_DEFAULT_ENABLED);
}
}
6 changes: 6 additions & 0 deletions newrelic-agent/src/main/resources/newrelic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ common: &default_settings
# Default is 10000. Setting to 0 will disable.
#max_samples_stored: 10000

# Whether the log events should include MDC from loggers with support for that.
include_mdc:

# When true, application logs will contain MDC data.
enabled: false

# The agent will generate metrics to indicate the number of
# application log events occurring at each distinct log level.
metrics:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ common: &default_settings
enabled: true
forwarding:
enabled: true
include_mdc:
enabled: false
max_samples_stored: 10000
metrics:
enabled: true
Expand Down

0 comments on commit e2aacd6

Please sign in to comment.