Skip to content

Commit

Permalink
[exporter/awsxray] Allow multiple log group names/arns to be set in e…
Browse files Browse the repository at this point in the history
…nvironmental variables (#33795)

**Description:** <Describe what has changed.>
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue.
Ex. Adding a feature - Explain what this achieves.-->

Cherry-picking from downstream:


[amazon-contributing#218](amazon-contributing#218)

* We allow users to set multiple log group names or arns using
environmental variable. We choose to use `&` to separate individual log
group name or arn because & is not allowed in log group names
(https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html)
and `&` implicitly means 'AND'.
* This PR adds the parsing logic in xray exporter to handle multiple log
group names/arns set in environmental variable.

**Link to tracking Issue:** <Issue number if applicable>
N/A

**Testing:** <Describe what testing was performed and which tests were
added.>
Unit Testing

**Documentation:** <Describe the documentation added.>
The readme for xray exporter is updated.
  • Loading branch information
pxaws authored Jul 3, 2024
1 parent 4e91206 commit f06baf9
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 4 deletions.
27 changes: 27 additions & 0 deletions .chloggen/log-integration.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: awsxrayexporter

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Allow multiple log group names/arns to be set in environmental variables

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [33795]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: [user]
7 changes: 5 additions & 2 deletions exporter/awsxrayexporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,11 @@ following values that are evaluated in this order:
In the case of multiple values are defined, the value with higher precedence will be used to set the `cloudwatch_logs` AWS Property.

`aws.log.group.arns` and `aws.log.group.names` are slice resource attributes that can be set programmatically.
Alternatively those resource attributes can be set using the [`OTEL_RESOURCE_ATTRIBUTES` environment variable](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md#specifying-resource-information-via-an-environment-variable). In this case only a single log group/log group arn can
be provided as a string rather than a slice.
Alternatively those resource attributes can be set using the [`OTEL_RESOURCE_ATTRIBUTES` environment variable](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md#specifying-resource-information-via-an-environment-variable). To set multiple log group names /log group arns, you can use `&`
to separate them. For example, 3 log groups `log-group1`, `log-group2`, and `log-group3` are set in the following command:
```
export OTEL_RESOURCE_ATTRIBUTES="aws.log.group.names=log-group1&log-group2&log-group3"
```

## AWS Credential Configuration

Expand Down
23 changes: 21 additions & 2 deletions exporter/awsxrayexporter/internal/translator/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,16 +272,35 @@ func makeAws(attributes map[string]pcommon.Value, resource pcommon.Resource, log
return filtered, awsData
}

func getLogGroupNamesOrArns(logGroupNamesOrArns string) []string {
// Split the input string by '&'
items := strings.Split(logGroupNamesOrArns, "&")

// Filter out empty strings
var result []string
for _, item := range items {
if item != "" {
result = append(result, item)
}
}

return result
}

// Normalize value to slice.
// 1. String values are converted to a slice of size 1 so that we can also handle resource
// 1. String values are converted to a slice so that we can also handle resource
// attributes that are set using the OTEL_RESOURCE_ATTRIBUTES
// (multiple log group names or arns are separate by & like this "log-group1&log-group2&log-group3")
// 2. Slices are kept as they are
// 3. Other types will result in a empty slice so that we avoid panic.
func normalizeToSlice(v pcommon.Value) pcommon.Slice {
switch v.Type() {
case pcommon.ValueTypeStr:
s := pcommon.NewSlice()
s.AppendEmpty().SetStr(v.Str())
logGroupNamesOrArns := getLogGroupNamesOrArns(v.Str())
for _, logGroupOrArn := range logGroupNamesOrArns {
s.AppendEmpty().SetStr(logGroupOrArn)
}
return s
case pcommon.ValueTypeSlice:
return v.Slice()
Expand Down
81 changes: 81 additions & 0 deletions exporter/awsxrayexporter/internal/translator/aws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,61 @@ func TestLogGroupsFromStringResourceAttribute(t *testing.T) {
assert.Contains(t, awsData.CWLogs, cwl1)
}

func TestLogGroupsWithAmpersandFromStringResourceAttribute(t *testing.T) {
cwl1 := awsxray.LogGroupMetadata{
LogGroup: awsxray.String("group1"),
}
cwl2 := awsxray.LogGroupMetadata{
LogGroup: awsxray.String("group2"),
}

attributes := make(map[string]pcommon.Value)
resource := pcommon.NewResource()

// normal cases
resource.Attributes().PutStr(conventions.AttributeAWSLogGroupNames, "group1&group2")
filtered, awsData := makeAws(attributes, resource, nil)
assert.NotNil(t, filtered)
assert.NotNil(t, awsData)
assert.Equal(t, 2, len(awsData.CWLogs))
assert.Contains(t, awsData.CWLogs, cwl1)
assert.Contains(t, awsData.CWLogs, cwl2)

// with extra & at end
resource.Attributes().PutStr(conventions.AttributeAWSLogGroupNames, "group1&group2&")
filtered, awsData = makeAws(attributes, resource, nil)
assert.NotNil(t, filtered)
assert.NotNil(t, awsData)
assert.Equal(t, 2, len(awsData.CWLogs))
assert.Contains(t, awsData.CWLogs, cwl1)
assert.Contains(t, awsData.CWLogs, cwl2)

// with extra & in the middle
resource.Attributes().PutStr(conventions.AttributeAWSLogGroupNames, "group1&&group2")
filtered, awsData = makeAws(attributes, resource, nil)
assert.NotNil(t, filtered)
assert.NotNil(t, awsData)
assert.Equal(t, 2, len(awsData.CWLogs))
assert.Contains(t, awsData.CWLogs, cwl1)
assert.Contains(t, awsData.CWLogs, cwl2)

// with extra & at the beginning
resource.Attributes().PutStr(conventions.AttributeAWSLogGroupNames, "&group1&group2")
filtered, awsData = makeAws(attributes, resource, nil)
assert.NotNil(t, filtered)
assert.NotNil(t, awsData)
assert.Equal(t, 2, len(awsData.CWLogs))
assert.Contains(t, awsData.CWLogs, cwl1)
assert.Contains(t, awsData.CWLogs, cwl2)

// with only &
resource.Attributes().PutStr(conventions.AttributeAWSLogGroupNames, "&")
filtered, awsData = makeAws(attributes, resource, nil)
assert.NotNil(t, filtered)
assert.NotNil(t, awsData)
assert.Equal(t, 0, len(awsData.CWLogs))
}

func TestLogGroupsInvalidType(t *testing.T) {
attributes := make(map[string]pcommon.Value)
resource := pcommon.NewResource()
Expand Down Expand Up @@ -493,6 +548,32 @@ func TestLogGroupsArnsFromStringResourceAttributes(t *testing.T) {
assert.Contains(t, awsData.CWLogs, cwl1)
}

func TestLogGroupsArnsWithAmpersandFromStringResourceAttributes(t *testing.T) {
group1 := "arn:aws:logs:us-east-1:123456789123:log-group:group1"
group2 := "arn:aws:logs:us-east-1:123456789123:log-group:group2"

cwl1 := awsxray.LogGroupMetadata{
LogGroup: awsxray.String("group1"),
Arn: awsxray.String(group1),
}
cwl2 := awsxray.LogGroupMetadata{
LogGroup: awsxray.String("group2"),
Arn: awsxray.String(group2),
}

attributes := make(map[string]pcommon.Value)
resource := pcommon.NewResource()
resource.Attributes().PutStr(conventions.AttributeAWSLogGroupARNs, "arn:aws:logs:us-east-1:123456789123:log-group:group1&arn:aws:logs:us-east-1:123456789123:log-group:group2")

filtered, awsData := makeAws(attributes, resource, nil)

assert.NotNil(t, filtered)
assert.NotNil(t, awsData)
assert.Equal(t, 2, len(awsData.CWLogs))
assert.Contains(t, awsData.CWLogs, cwl1)
assert.Contains(t, awsData.CWLogs, cwl2)
}

func TestLogGroupsFromConfig(t *testing.T) {
cwl1 := awsxray.LogGroupMetadata{
LogGroup: awsxray.String("logGroup1"),
Expand Down

0 comments on commit f06baf9

Please sign in to comment.