Skip to content

Commit

Permalink
add logprocessor to agent
Browse files Browse the repository at this point in the history
  • Loading branch information
kryalama authored and trask committed Jun 1, 2021
1 parent ea2689e commit 3561f01
Show file tree
Hide file tree
Showing 10 changed files with 880 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,23 @@ protected static AttributeProcessor.IncludeExclude getNormalizedIncludeExclude(P
return exclude;
}


public static abstract class IncludeExclude {
// Function to compare span with user provided span names or span patterns
public abstract boolean isMatch(SpanData span);
public abstract boolean isMatch(SpanData span, boolean isLog);

}

// ok to have this class cover both spanNames and logNames
public static class StrictIncludeExclude extends IncludeExclude {
private final List<ProcessorAttribute> attributes;
private final List<String> spanNames;
private final List<String> logNames;

public StrictIncludeExclude(List<ProcessorAttribute> attributes, List<String> spanNames) {
public StrictIncludeExclude(List<ProcessorAttribute> attributes, List<String> spanNames, List<String> logNames) {
this.attributes = attributes;
this.spanNames = spanNames;
this.logNames = logNames;
}

public static StrictIncludeExclude create(ProcessorIncludeExclude includeExclude) {
Expand All @@ -61,18 +64,34 @@ public static StrictIncludeExclude create(ProcessorIncludeExclude includeExclude
if (spanNames == null) {
spanNames = new ArrayList<>();
}
return new StrictIncludeExclude(attributes, spanNames);
List<String> logNames = includeExclude.logNames;
if (logNames == null) {
logNames = new ArrayList<>();
}

return new StrictIncludeExclude(attributes, spanNames, logNames);
}

// Function to compare span with user provided span names
public boolean isMatch(SpanData span) {
if (!spanNames.isEmpty() && !spanNames.contains(span.getName())) {
// span name doesn't match
return false;
// Function to compare span with user provided span names and log names
public boolean isMatch(SpanData span, boolean isLog) {

if(spanNames.isEmpty() && logNames.isEmpty()) {
// check attributes for both spans and logs
return this.checkAttributes(span);
}
if(isLog) {
if(logNames.isEmpty()) return false;
if(!logNames.isEmpty() && !logNames.contains(span.getName())) return false;
} else {
if(spanNames.isEmpty()) return false;
if(!spanNames.isEmpty() && !spanNames.contains(span.getName())) return false;
}

return this.checkAttributes(span);
}



// Function to compare span with user provided attributes list
private boolean checkAttributes(SpanData span) {
for (ProcessorAttribute attribute : attributes) {
Expand All @@ -98,10 +117,12 @@ private boolean checkAttributes(SpanData span) {
public static class RegexpIncludeExclude extends IncludeExclude {

private final List<Pattern> spanPatterns;
private final List<Pattern> logPatterns;
private final Map<AttributeKey<?>, Pattern> attributeValuePatterns;

public RegexpIncludeExclude(List<Pattern> spanPatterns, Map<AttributeKey<?>, Pattern> attributeValuePatterns) {
public RegexpIncludeExclude(List<Pattern> spanPatterns, List<Pattern> logPatterns, Map<AttributeKey<?>, Pattern> attributeValuePatterns) {
this.spanPatterns = spanPatterns;
this.logPatterns = logPatterns;
this.attributeValuePatterns = attributeValuePatterns;
}

Expand All @@ -115,23 +136,31 @@ public static RegexpIncludeExclude create(ProcessorIncludeExclude includeExclude
}
}
}

List<Pattern> spanPatterns = new ArrayList<>();
if (includeExclude.spanNames != null) {
for (String regex : includeExclude.spanNames) {
spanPatterns.add(Pattern.compile(regex));
}
}

return new RegexpIncludeExclude(spanPatterns, attributeKeyValuePatterns);
List<Pattern> logPatterns = new ArrayList<>();
if (includeExclude.logNames != null) {
for (String regex : includeExclude.logNames) {
logPatterns.add(Pattern.compile(regex));
}
}

return new RegexpIncludeExclude(spanPatterns, logPatterns, attributeKeyValuePatterns);
}

// Function to compare span attribute value with user provided value
private static boolean isAttributeValueMatch(String attributeValue, Pattern valuePattern) {
return valuePattern.matcher(attributeValue).find();
}

private boolean isPatternFound(SpanData span) {
for (Pattern pattern : spanPatterns) {
private static boolean isPatternFound(SpanData span, List<Pattern> patterns) {
for (Pattern pattern : patterns) {
if (pattern.matcher(span.getName()).find()) {
// pattern matches the span!!!
return true;
Expand All @@ -142,10 +171,21 @@ private boolean isPatternFound(SpanData span) {
}

// Function to compare span with user provided span patterns
public boolean isMatch(SpanData span) {
if (!spanPatterns.isEmpty() && !isPatternFound(span)) {
return false;
public boolean isMatch(SpanData span, boolean isLog) {

if(spanPatterns.isEmpty() && logPatterns.isEmpty()) {
// check attributes for both spans and logs
return checkAttributes(span);
}

if(isLog) {
if(logPatterns.isEmpty()) return false;
if(!logPatterns.isEmpty() && !isPatternFound(span, logPatterns)) return false;
} else {
if(spanPatterns.isEmpty()) return false;
if(!spanPatterns.isEmpty() && !isPatternFound(span, spanPatterns)) return false;
}

return checkAttributes(span);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@ public CompletableResultCode export(Collection<SpanData> spans) {

private SpanData process(SpanData span) {
IncludeExclude include = attributeProcessor.getInclude();
if (include != null && !include.isMatch(span)) {
boolean isLog = ProcessorUtil.isSpanOfTypeLog(span);
if (include != null && !include.isMatch(span, isLog)) {
//If Not included we can skip further processing
return span;
}
IncludeExclude exclude = attributeProcessor.getExclude();
if (exclude != null && exclude.isMatch(span)) {
if (exclude != null && exclude.isMatch(span, isLog)) {
return span;
}
return attributeProcessor.processActions(span);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.microsoft.applicationinsights.agent.internal.processors;

import com.microsoft.applicationinsights.agent.internal.processors.AgentProcessor.IncludeExclude;
import com.microsoft.applicationinsights.agent.internal.wasbootstrap.configuration.Configuration.ProcessorConfig;
import com.microsoft.applicationinsights.customExceptions.FriendlyException;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.export.SpanExporter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class ExporterWithLogProcessor implements SpanExporter {

private final SpanExporter delegate;
private final SpanProcessor logProcessor;

// caller should check config.isValid before creating
public ExporterWithLogProcessor(ProcessorConfig config, SpanExporter delegate) throws FriendlyException {
config.validate();
logProcessor = SpanProcessor.create(config);
this.delegate = delegate;
}

@Override
public CompletableResultCode export(Collection<SpanData> spans) {
// we need to filter attributes before passing on to delegate

List<SpanData> copy = new ArrayList<>();
for (SpanData span : spans) {
copy.add(process(span));
}
return delegate.export(copy);

}

private SpanData process(SpanData span) {
IncludeExclude include = logProcessor.getInclude();
if(!ProcessorUtil.isSpanOfTypeLog(span)) {
return span;
}
if (include != null && !include.isMatch(span, true)) {
//If Not included we can skip further processing
return span;
}
IncludeExclude exclude = logProcessor.getExclude();
if (exclude != null && exclude.isMatch(span, true)) {
return span;
}

SpanData updatedSpan = logProcessor.processFromAttributes(span);
return logProcessor.processToAttributes(updatedSpan);
}

@Override
public CompletableResultCode flush() {
return delegate.flush();
}

@Override
public CompletableResultCode shutdown() {
return delegate.shutdown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,15 @@ public CompletableResultCode export(Collection<SpanData> spans) {

private SpanData process(SpanData span) {
IncludeExclude include = spanProcessor.getInclude();
if (include != null && !include.isMatch(span)) {
if(ProcessorUtil.isSpanOfTypeLog(span)) {
return span;
}
if (include != null && !include.isMatch(span, false)) {
//If Not included we can skip further processing
return span;
}
IncludeExclude exclude = spanProcessor.getExclude();
if (exclude != null && exclude.isMatch(span)) {
if (exclude != null && exclude.isMatch(span, false)) {
return span;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.microsoft.applicationinsights.agent.internal.processors;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.sdk.trace.data.SpanData;

public class ProcessorUtil {
private static final AttributeKey<Boolean> AI_LOG_KEY = AttributeKey.booleanKey("applicationinsights.internal.log");
public static boolean isSpanOfTypeLog(SpanData span) {
Boolean isLog = span.getAttributes().get(AI_LOG_KEY);
return isLog != null && isLog;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

import com.microsoft.applicationinsights.TelemetryClient;
import com.microsoft.applicationinsights.agent.Exporter;
import com.microsoft.applicationinsights.agent.internal.processors.ExporterWithLogProcessor;
import com.microsoft.applicationinsights.agent.internal.wasbootstrap.configuration.Configuration;
import com.microsoft.applicationinsights.agent.internal.wasbootstrap.configuration.Configuration.ProcessorConfig;
import com.microsoft.applicationinsights.agent.internal.wasbootstrap.configuration.Configuration.ProcessorType;
import com.microsoft.applicationinsights.agent.internal.Global;
import com.microsoft.applicationinsights.agent.internal.processors.ExporterWithAttributeProcessor;
import com.microsoft.applicationinsights.agent.internal.processors.ExporterWithSpanProcessor;
Expand Down Expand Up @@ -51,16 +51,13 @@ public void configure(SdkTracerProviderBuilder tracerProvider) {
if (!processors.isEmpty()) {
SpanExporter currExporter = null;
for (ProcessorConfig processorConfig : processors) {

if (currExporter == null) {
currExporter = processorConfig.type == ProcessorType.attribute ?
new ExporterWithAttributeProcessor(processorConfig, new Exporter(telemetryClient)) :
new ExporterWithSpanProcessor(processorConfig, new Exporter(telemetryClient));

} else {
currExporter = processorConfig.type == ProcessorType.attribute ?
new ExporterWithAttributeProcessor(processorConfig, currExporter) :
new ExporterWithSpanProcessor(processorConfig, currExporter);
if(processorConfig.type != null) { // Added this condition to resolve spotbugs NP_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD issue
switch (processorConfig.type) {
case attribute : currExporter = new ExporterWithAttributeProcessor(processorConfig, currExporter); break;
case span : currExporter = new ExporterWithSpanProcessor(processorConfig, currExporter); break;
case log: currExporter = new ExporterWithLogProcessor(processorConfig, currExporter); break;
default: throw new IllegalStateException("Not an expected ProcessorType: "+processorConfig.type);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -454,8 +454,8 @@ public void validate(ProcessorType processorType, IncludeExclude includeExclude)
}

private void validAttributeProcessorIncludeExclude(IncludeExclude includeExclude) throws FriendlyException {
if (spanNames.isEmpty() && attributes.isEmpty()) {
throw new FriendlyException("An attribute processor configuration has an " + includeExclude + " section with no \"spanNames\" and no \"attributes\".",
if (attributes.isEmpty() && spanNames.isEmpty() && logNames.isEmpty()) {
throw new FriendlyException("An attribute processor configuration has an " + includeExclude + " section with no \"spanNames\", \"logNames\" and no \"attributes\".",
"Please provide at least one of \"spanNames\" or \"attributes\" under the " + includeExclude + " section of the attribute processor configuration. " +
"Learn more about attribute processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
Expand Down
Loading

0 comments on commit 3561f01

Please sign in to comment.