Skip to content

Renovate/GitHub.com cloudfy azuremonitor 38432 #38450

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
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
10 changes: 10 additions & 0 deletions exporter/azuremonitorexporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ Exception events are saved to the Application Insights `exception` table.
This exporter saves log records to Application Insights `traces` table.
[TraceId](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#field-traceid) is mapped to `operation_id` column and [SpanId](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#field-spanid) is mapped to `operation_parentId` column.

### Exceptions

This exporter saves exception records to Application Insights `exceptions` table when log records indicate an excetion [specification](https://opentelemetry.io/docs/specs/otel/trace/exceptions/).

Exceptions must be log records with `SeverityNumber` of 17 (Error) and the following attributes MUST be filled out:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls update based on current implementation


* exception.message
* exception.stacktrace
* exception.type

### Metrics

This exporter saves metrics to Application Insights `customMetrics` table.
Expand Down
95 changes: 76 additions & 19 deletions exporter/azuremonitorexporter/log_to_envelope.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import (
"time"

"github.com/microsoft/ApplicationInsights-Go/appinsights/contracts"
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/traceutil"
"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/plog"
conventions "go.opentelemetry.io/collector/semconv/v1.12.0"
"go.uber.org/zap"

"github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/traceutil"
)

type logPacker struct {
Expand All @@ -25,31 +25,65 @@ func (packer *logPacker) LogRecordToEnvelope(logRecord plog.LogRecord, resource

data := contracts.NewData()

messageData := contracts.NewMessageData()
messageData.Properties = make(map[string]string)
logAttributeMap := logRecord.Attributes()

if hasRequiredKeys(logAttributeMap, conventions.AttributeExceptionMessage, conventions.AttributeExceptionType) {
// handle envelope for exceptions
exceptionData := contracts.NewExceptionData()
exceptionData.Properties = make(map[string]string)
exceptionData.SeverityLevel = packer.toAiSeverityLevel(logRecord.SeverityNumber())
exceptionData.ProblemId = logRecord.SeverityText()

exceptionDetails := mapIncomingAttributeMapExceptionDetail(logAttributeMap)
exceptionData.Exceptions = append(exceptionData.Exceptions, exceptionDetails)

envelope.Name = exceptionData.EnvelopeName("")

data.BaseData = exceptionData
data.BaseType = exceptionData.BaseType()
envelope.Data = data

envelope.Tags[contracts.OperationId] = traceutil.TraceIDToHexOrEmptyString(logRecord.TraceID())
envelope.Tags[contracts.OperationParentId] = traceutil.SpanIDToHexOrEmptyString(logRecord.SpanID())

resourceAttributes := resource.Attributes()
applyResourcesToDataProperties(exceptionData.Properties, resourceAttributes)
applyInstrumentationScopeValueToDataProperties(exceptionData.Properties, instrumentationScope)
applyCloudTagsToEnvelope(envelope, resourceAttributes)
applyInternalSdkVersionTagToEnvelope(envelope)

setAttributesAsProperties(logAttributeMap, exceptionData.Properties)

messageData.SeverityLevel = packer.toAiSeverityLevel(logRecord.SeverityNumber())
packer.sanitize(func() []string { return exceptionData.Sanitize() })

messageData.Message = logRecord.Body().AsString()
} else {
// handle envelope for messages (traces)
messageData := contracts.NewMessageData()
messageData.Properties = make(map[string]string)

envelope.Tags[contracts.OperationId] = traceutil.TraceIDToHexOrEmptyString(logRecord.TraceID())
envelope.Tags[contracts.OperationParentId] = traceutil.SpanIDToHexOrEmptyString(logRecord.SpanID())
messageData.SeverityLevel = packer.toAiSeverityLevel(logRecord.SeverityNumber())
messageData.Message = logRecord.Body().AsString()

envelope.Name = messageData.EnvelopeName("")
envelope.Name = messageData.EnvelopeName("")

data.BaseData = messageData
data.BaseType = messageData.BaseType()
envelope.Data = data
data.BaseData = messageData
data.BaseType = messageData.BaseType()
envelope.Data = data

resourceAttributes := resource.Attributes()
applyResourcesToDataProperties(messageData.Properties, resourceAttributes)
applyInstrumentationScopeValueToDataProperties(messageData.Properties, instrumentationScope)
applyCloudTagsToEnvelope(envelope, resourceAttributes)
applyInternalSdkVersionTagToEnvelope(envelope)
envelope.Tags[contracts.OperationId] = traceutil.TraceIDToHexOrEmptyString(logRecord.TraceID())
envelope.Tags[contracts.OperationParentId] = traceutil.SpanIDToHexOrEmptyString(logRecord.SpanID())

setAttributesAsProperties(logRecord.Attributes(), messageData.Properties)
resourceAttributes := resource.Attributes()
applyResourcesToDataProperties(messageData.Properties, resourceAttributes)
applyInstrumentationScopeValueToDataProperties(messageData.Properties, instrumentationScope)
applyCloudTagsToEnvelope(envelope, resourceAttributes)
applyInternalSdkVersionTagToEnvelope(envelope)

setAttributesAsProperties(logAttributeMap, messageData.Properties)

packer.sanitize(func() []string { return messageData.Sanitize() })
}

packer.sanitize(func() []string { return messageData.Sanitize() })
packer.sanitize(func() []string { return envelope.Sanitize() })
packer.sanitize(func() []string { return contracts.SanitizeTags(envelope.Tags) })

Expand Down Expand Up @@ -97,3 +131,26 @@ func timestampFromLogRecord(lr plog.LogRecord) pcommon.Timestamp {

return pcommon.NewTimestampFromTime(timeNow())
}

func mapIncomingAttributeMapExceptionDetail(attributemap pcommon.Map) *contracts.ExceptionDetails {
exceptionDetails := contracts.NewExceptionDetails()
if message, exists := attributemap.Get(conventions.AttributeExceptionMessage); exists {
exceptionDetails.Message = message.Str()
}
if typeName, exists := attributemap.Get(conventions.AttributeExceptionType); exists {
exceptionDetails.TypeName = typeName.Str()
}
if stackTrace, exists := attributemap.Get(conventions.AttributeExceptionStacktrace); exists {
exceptionDetails.Stack = stackTrace.Str()
}
return exceptionDetails
}
func hasRequiredKeys(attrMap pcommon.Map, keys ...string) bool {
for _, key := range keys {
_, exists := attrMap.Get(key)
if !exists {
return false
}
}
return true
}
Loading