Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public static Map<String, String> getLogEventLinkingMetadata(TraceMetadata trace
logEventLinkingMetadata.put(HOSTNAME, hostname);
}

String entityName = getEntityName(agentConfig);
String entityName = rpmService.getApplicationName();
if (!entityName.isEmpty()) {
logEventLinkingMetadata.put(ENTITY_NAME, entityName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,11 @@ public interface ApplicationLoggingConfig {
* @return a Set of excluded labels
*/
Set<String> getLogLabelsExcludeSet();

/**
* Return the enabled flag for the auto_app_naming_association flag
*
* @return true if auto_app_naming_association is enabled
*/
boolean isAutoAppNamingAssociationEnabled();
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,5 +140,10 @@ public Map<String, String> removeExcludedLogLabels(Map<String, String> labels) {
public Set<String> getLogLabelsExcludeSet() {
return applicationLoggingForwardingConfig.getLoggingLabelsExcludeSet();
}

@Override
public boolean isAutoAppNamingAssociationEnabled() {
return applicationLoggingForwardingConfig.isAutoAppNamingAssociationEnabled();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package com.newrelic.agent.config;

import com.newrelic.agent.Agent;
import com.newrelic.api.agent.NewRelic;

import java.util.Collections;
import java.util.List;
Expand All @@ -19,12 +20,16 @@ public class ApplicationLoggingForwardingConfig extends BaseConfig {
public static final String ROOT = "forwarding";
public static final String ENABLED = "enabled";
public static final String MAX_SAMPLES_STORED = "max_samples_stored";
public static final String AUTO_APP_NAMING_ASSOC = "auto_app_naming_association";

public static final boolean DEFAULT_ENABLED = true;
public static final int DEFAULT_MAX_SAMPLES_STORED = 10000;
public static final boolean DEFAULT_AUTO_APP_NAMING_ASSOC = false;

private final boolean enabled;
private final int maxSamplesStored;
private final boolean autoAppNamingAssociation;

private final ApplicationLoggingContextDataConfig contextDataConfig;
private final ApplicationLoggingLabelsConfig loggingLabelsConfig;

Expand All @@ -35,6 +40,7 @@ public ApplicationLoggingForwardingConfig(Map<String, Object> props, String pare
enabled = storedMoreThan0 && !highSecurity && getProperty(ENABLED, DEFAULT_ENABLED);
contextDataConfig = createContextDataConfig(highSecurity);
loggingLabelsConfig = createLoggingLabelsConfig();
autoAppNamingAssociation = initAutoAppNamingAssociationEnabledFlag();
}

private int initMaxSamplesStored() {
Expand All @@ -57,6 +63,15 @@ private ApplicationLoggingLabelsConfig createLoggingLabelsConfig() {
return new ApplicationLoggingLabelsConfig(labelsProps, systemPropertyPrefix);
}

private boolean initAutoAppNamingAssociationEnabledFlag() {
// If enable_auto_app_naming is false, this association flag must also be false
if (!NewRelic.getAgent().getConfig().getValue(AgentConfigImpl.ENABLE_AUTO_APP_NAMING, false)) {
return false;
} else {
return getProperty(AUTO_APP_NAMING_ASSOC, DEFAULT_AUTO_APP_NAMING_ASSOC);
}
}

public boolean getEnabled() {
return enabled;
}
Expand All @@ -81,6 +96,10 @@ public boolean isLogLabelsEnabled() {
return enabled && loggingLabelsConfig.getEnabled();
}

public boolean isAutoAppNamingAssociationEnabled() {
return autoAppNamingAssociation;
}

public Map<String, String> removeExcludedLabels(Map<String, String> labels) {
return loggingLabelsConfig.removeExcludedLabels(labels);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.newrelic.agent.AgentLinkingMetadata;
import com.newrelic.agent.ExtendedTransactionListener;
import com.newrelic.agent.Harvestable;
import com.newrelic.agent.IRPMService;
import com.newrelic.agent.MetricNames;
import com.newrelic.agent.TraceMetadataImpl;
import com.newrelic.agent.Transaction;
Expand Down Expand Up @@ -74,6 +75,7 @@ public class LogSenderServiceImpl extends AbstractService implements LogSenderSe
// to properly calculate the per harvest cycle maxSamplesStored
// we'll default to 5000, unless overridden
volatile long reportPeriodInMillis = 5000;
private volatile boolean autoAppNamingAssociationEnabled;
// Key is app name, value is collection of per-transaction log events for next harvest for that app.
private final ConcurrentHashMap<String, DistributedSamplingPriorityQueue<LogEvent>> reservoirForApp = new ConcurrentHashMap<>();

Expand Down Expand Up @@ -123,6 +125,7 @@ public void configChanged(String appName, AgentConfig agentConfig) {
maxSamplesStored = (int) (appLoggingConfig.getMaxSamplesStored()*(reportPeriodInMillis / 60000.0));
forwardingEnabled = appLoggingConfig.isForwardingEnabled();
contextDataKeyFilter = createContextDataKeyFilter(appLoggingConfig);
autoAppNamingAssociationEnabled = appLoggingConfig.isAutoAppNamingAssociationEnabled();

boolean metricsEnabled = appLoggingConfig.isMetricsEnabled();
boolean localDecoratingEnabled = appLoggingConfig.isLocalDecoratingEnabled();
Expand Down Expand Up @@ -167,6 +170,7 @@ public LogSenderServiceImpl() {

maxSamplesStored = (int) (appLoggingConfig.getMaxSamplesStored()*(reportPeriodInMillis / 60000.0));
forwardingEnabled = appLoggingConfig.isForwardingEnabled();
autoAppNamingAssociationEnabled = appLoggingConfig.isAutoAppNamingAssociationEnabled();
contextDataKeyFilter = createContextDataKeyFilter(appLoggingConfig);
logLabelsEnabled = appLoggingConfig.isLogLabelsEnabled();
labels = appLoggingConfig.removeExcludedLogLabels(config.getLabelsConfig().getLabels());
Expand Down Expand Up @@ -361,7 +365,7 @@ private void createAndStoreEvent(String appName, Map<LogAttributeKey, ?> attribu
return;
}
DistributedSamplingPriorityQueue<LogEvent> eventList = getReservoir(appName);
eventList.add(createValidatedEvent(attributes, contextDataKeyFilter));
eventList.add(createValidatedEvent(attributes, contextDataKeyFilter, autoAppNamingAssociationEnabled));
Agent.LOG.finest(MessageFormat.format("Added event of type {0}", LOG_EVENT_TYPE));
}

Expand Down Expand Up @@ -524,11 +528,20 @@ private static String mapInternString(String value) {
*
* @param attributes Map of attributes to create a LogEvent from
* @param contextDataKeyFilter
* @param autoAppNamingAssociationEnabled true if enabled_auto_app_naming and auto_app_naming_association
* is also true. If true, logs will be associated with their corresponding entity and not the roll up
* entity.
*
* @return LogEvent instance
*/
private static LogEvent createValidatedEvent(Map<LogAttributeKey, ?> attributes, ExcludeIncludeFilter contextDataKeyFilter) {
private static LogEvent createValidatedEvent(Map<LogAttributeKey, ?> attributes, ExcludeIncludeFilter contextDataKeyFilter,
boolean autoAppNamingAssociationEnabled) {
// Insure we get the correct RPMService instance if auto app naming is enabled
Transaction txn = ServiceFactory.getTransactionService().getTransaction(false);
IRPMService rpmService = (txn == null || !autoAppNamingAssociationEnabled) ? ServiceFactory.getRPMService() : ServiceFactory.getRPMServiceManager().getOrCreateRPMService(txn.getApplicationName());

Map<String, String> logEventLinkingMetadata = AgentLinkingMetadata.getLogEventLinkingMetadata(TraceMetadataImpl.INSTANCE,
ServiceFactory.getConfigService(), ServiceFactory.getRPMService());
ServiceFactory.getConfigService(), rpmService);
// Initialize new logEventAttributes map with agent linking metadata
Map<String, Object> logEventAttributes = new HashMap<>(logEventLinkingMetadata);

Expand Down Expand Up @@ -621,11 +634,13 @@ public Logs getTransactionLogs(AgentConfig config) {
public static final class TransactionLogs implements Logs {
private final Queue<LogEvent> events;
private final ExcludeIncludeFilter contextDataKeyFilter;
private final boolean autoAppNamingAssociationEnabled;

TransactionLogs(AgentConfig config, ExcludeIncludeFilter contextDataKeyFilter) {
int maxSamplesStored = config.getApplicationLoggingConfig().getMaxSamplesStored();
events = maxSamplesStored == 0 ? NoOpQueue.getInstance() : new LinkedBlockingQueue<>(maxSamplesStored);
this.contextDataKeyFilter = contextDataKeyFilter;
autoAppNamingAssociationEnabled = config.getApplicationLoggingConfig().isAutoAppNamingAssociationEnabled();
}

@Override
Expand All @@ -635,7 +650,7 @@ public void recordLogEvent(Map<LogAttributeKey, ?> attributes) {
return;
}

LogEvent event = createValidatedEvent(attributes, contextDataKeyFilter);
LogEvent event = createValidatedEvent(attributes, contextDataKeyFilter, autoAppNamingAssociationEnabled);
if (events.offer(event)) {
Agent.LOG.log(Level.FINEST, "Added event of type {0} in Transaction.", LOG_EVENT_TYPE);
} else {
Expand Down
5 changes: 5 additions & 0 deletions newrelic-agent/src/main/resources/newrelic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ common: &default_settings
# When true, application logs will be forwarded to New Relic. The default is true.
enabled: true

# When true and "enable_auto_app_naming" is also true, log events will be sent
# to their corresponding named entity rather than the roll up entity.
# Default is false.
auto_app_naming_association: false

# Application log events are collected up to the configured amount. Afterwards,
# events are sampled to maintain an even distribution across the harvest cycle.
# Default is 10000. Setting to 0 will disable.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public void getLinkingMetadataWithEmptyTraceAttributes() {
when(configServiceMock.getDefaultAgentConfig()).thenReturn(agentConfigMock);
when(agentConfigMock.getApplicationName()).thenReturn(expectedEntityName);
when(rpmServiceMock.getEntityGuid()).thenReturn(expectedEntityGuid);
when(rpmServiceMock.getApplicationName()).thenReturn(expectedEntityName);

// Then
Map<String, String> linkingMetadata = AgentLinkingMetadata.getLinkingMetadata(traceMetadataMock, ServiceFactory.getConfigService(),
Expand Down Expand Up @@ -133,6 +134,7 @@ public void getLogEventLinkingMetadata() {
when(configServiceMock.getDefaultAgentConfig()).thenReturn(agentConfigMock);
when(agentConfigMock.getApplicationName()).thenReturn(expectedEntityName);
when(rpmServiceMock.getEntityGuid()).thenReturn(expectedEntityGuid);
when(rpmServiceMock.getApplicationName()).thenReturn(expectedEntityName);

// Then
Map<String, String> linkingMetadata = AgentLinkingMetadata.getLogEventLinkingMetadata(traceMetadataMock, ServiceFactory.getConfigService(),
Expand Down Expand Up @@ -177,6 +179,7 @@ public void getLogEventLinkingMetadataWithEmptyTraceAttributes() {
when(configServiceMock.getDefaultAgentConfig()).thenReturn(agentConfigMock);
when(agentConfigMock.getApplicationName()).thenReturn(expectedEntityName);
when(rpmServiceMock.getEntityGuid()).thenReturn(expectedEntityGuid);
when(rpmServiceMock.getApplicationName()).thenReturn(expectedEntityName);

// Then
Map<String, String> linkingMetadata = AgentLinkingMetadata.getLogEventLinkingMetadata(traceMetadataMock, ServiceFactory.getConfigService(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public void defaultForwardingConfig() {
ApplicationLoggingForwardingConfig config = new ApplicationLoggingForwardingConfig(localProps, ApplicationLoggingConfigImpl.SYSTEM_PROPERTY_ROOT,
false);
assertTrue(config.getEnabled());
assertFalse(config.isAutoAppNamingAssociationEnabled());
}

@Test
Expand Down
Loading