Skip to content

Commit df890d6

Browse files
axwFiery-Fenix
authored andcommitted
New component: awslogsencodingextension (open-telemetry#38816)
#### Description This is a new encoding extension for decoding logs from various AWS services. We will start with the CloudWatch Logs subscription filter format and expand to other formats, including CloudFront access logs, VPC flow logs (text/parquet), and more. #### Link to tracking issue First part of open-telemetry#38627 #### Testing Added basic unit tests. #### Documentation README.
1 parent 6b95ddd commit df890d6

25 files changed

+585
-0
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: new_component
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: awslogsencodingextension
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add AWS Logs Encoding Extension to support decoding logs produced by AWS services
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [38627]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: [user]

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ extension/cgroupruntimeextension/ @open-telemetry
9494
extension/encoding/ @open-telemetry/collector-contrib-approvers @atoulme @dao-jun @dmitryax @MovieStoreGuy @VihasMakwana
9595
extension/encoding/avrologencodingextension/ @open-telemetry/collector-contrib-approvers @thmshmm
9696
extension/encoding/awscloudwatchmetricstreamsencodingextension/ @open-telemetry/collector-contrib-approvers @axw @constanca-m
97+
extension/encoding/awslogsencodingextension/ @open-telemetry/collector-contrib-approvers @axw @constanca-m
9798
extension/encoding/googlecloudlogentryencodingextension/ @open-telemetry/collector-contrib-approvers @alexvanboxel
9899
extension/encoding/jaegerencodingextension/ @open-telemetry/collector-contrib-approvers @MovieStoreGuy @atoulme
99100
extension/encoding/jsonlogencodingextension/ @open-telemetry/collector-contrib-approvers @VihasMakwana @atoulme

.github/ISSUE_TEMPLATE/bug_report.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ body:
9797
- extension/encoding
9898
- extension/encoding/avrologencoding
9999
- extension/encoding/awscloudwatchmetricstreamsencoding
100+
- extension/encoding/awslogsencoding
100101
- extension/encoding/googlecloudlogentryencoding
101102
- extension/encoding/jaegerencoding
102103
- extension/encoding/jsonlogencoding

.github/ISSUE_TEMPLATE/feature_request.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ body:
9191
- extension/encoding
9292
- extension/encoding/avrologencoding
9393
- extension/encoding/awscloudwatchmetricstreamsencoding
94+
- extension/encoding/awslogsencoding
9495
- extension/encoding/googlecloudlogentryencoding
9596
- extension/encoding/jaegerencoding
9697
- extension/encoding/jsonlogencoding

.github/ISSUE_TEMPLATE/other.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ body:
9191
- extension/encoding
9292
- extension/encoding/avrologencoding
9393
- extension/encoding/awscloudwatchmetricstreamsencoding
94+
- extension/encoding/awslogsencoding
9495
- extension/encoding/googlecloudlogentryencoding
9596
- extension/encoding/jaegerencoding
9697
- extension/encoding/jsonlogencoding

.github/ISSUE_TEMPLATE/unmaintained.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ body:
9696
- extension/encoding
9797
- extension/encoding/avrologencoding
9898
- extension/encoding/awscloudwatchmetricstreamsencoding
99+
- extension/encoding/awslogsencoding
99100
- extension/encoding/googlecloudlogentryencoding
100101
- extension/encoding/jaegerencoding
101102
- extension/encoding/jsonlogencoding

.github/component_labels.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ extension/cgroupruntimeextension extension/cgroupruntime
7575
extension/encoding extension/encoding
7676
extension/encoding/avrologencodingextension extension/encoding/avrologencoding
7777
extension/encoding/awscloudwatchmetricstreamsencodingextension extension/encoding/awscloudwatchmetricstreams
78+
extension/encoding/awslogsencodingextension extension/encoding/awslogsencoding
7879
extension/encoding/googlecloudlogentryencodingextension extension/encoding/googlecloudlogentryencoding
7980
extension/encoding/jaegerencodingextension extension/encoding/jaegerencoding
8081
extension/encoding/jsonlogencodingextension extension/encoding/jsonlogencoding
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include ../../../Makefile.Common
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# AWS Logs encoding extension
2+
3+
<!-- status autogenerated section -->
4+
| Status | |
5+
| ------------- |-----------|
6+
| Stability | [development] |
7+
| Distributions | [] |
8+
| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aextension%2Fawslogsencoding%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aextension%2Fawslogsencoding) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aextension%2Fawslogsencoding%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aextension%2Fawslogsencoding) |
9+
| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@axw](https://www.github.com/axw), [@constanca-m](https://www.github.com/constanca-m) |
10+
11+
[development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development
12+
<!-- end autogenerated section -->
13+
14+
This extension unmarshals logs encoded in formats produced by AWS services, including:
15+
- [Amazon CloudWatch Logs Subscription Filters](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html).
16+
- (More to be added later.)
17+
18+
Example for Amazon CloudWatch Logs Subscription Filters:
19+
```yaml
20+
extensions:
21+
awslogs_encoding/cloudwatch:
22+
format: cloudwatch_logs_subscription_filter
23+
24+
receivers:
25+
awsfirehose:
26+
endpoint: :1234
27+
encoding: awslogs_encoding/cloudwatch
28+
```
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package awslogsencodingextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/awslogsencodingextension"
5+
6+
import (
7+
"errors"
8+
9+
"go.opentelemetry.io/collector/pdata/plog"
10+
)
11+
12+
type cloudWatchLogsSubscriptionFilterUnmarshaler struct{}
13+
14+
func (cloudWatchLogsSubscriptionFilterUnmarshaler) UnmarshalLogs(_ []byte) (plog.Logs, error) {
15+
// TODO implement this
16+
return plog.Logs{}, errors.New("not implemented")
17+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package awslogsencodingextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/awslogsencodingextension"
5+
6+
import (
7+
"fmt"
8+
9+
"go.opentelemetry.io/collector/confmap/xconfmap"
10+
)
11+
12+
var _ xconfmap.Validator = (*Config)(nil)
13+
14+
const (
15+
formatCloudWatchLogsSubscriptionFilter = "cloudwatch_logs_subscription_filter"
16+
)
17+
18+
var supportedFormats = []string{formatCloudWatchLogsSubscriptionFilter}
19+
20+
type Config struct {
21+
// Format defines the AWS logs format.
22+
//
23+
// Valid values are:
24+
// - cloudwatch_logs_subscription_filter
25+
//
26+
Format string `mapstructure:"format"`
27+
}
28+
29+
func (cfg *Config) Validate() error {
30+
switch cfg.Format {
31+
case "":
32+
return fmt.Errorf("format unspecified, expected one of %q", supportedFormats)
33+
case formatCloudWatchLogsSubscriptionFilter:
34+
// valid
35+
default:
36+
return fmt.Errorf("unsupported format %q, expected one of %q", cfg.Format, supportedFormats)
37+
}
38+
return nil
39+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package awslogsencodingextension
5+
6+
import (
7+
"path/filepath"
8+
"strings"
9+
"testing"
10+
11+
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
13+
"go.opentelemetry.io/collector/component"
14+
"go.opentelemetry.io/collector/confmap/confmaptest"
15+
"go.opentelemetry.io/collector/confmap/xconfmap"
16+
17+
"github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/awslogsencodingextension/internal/metadata"
18+
)
19+
20+
func TestLoadConfig(t *testing.T) {
21+
t.Parallel()
22+
23+
cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml"))
24+
require.NoError(t, err)
25+
26+
tests := []struct {
27+
id component.ID
28+
expected component.Config
29+
expectedErr string
30+
}{
31+
{
32+
id: component.NewIDWithName(metadata.Type, ""),
33+
expectedErr: `format unspecified, expected one of ["cloudwatch_logs_subscription_filter"]`,
34+
},
35+
{
36+
id: component.NewIDWithName(metadata.Type, "cloudwatch_logs_subscription_filter"),
37+
expected: &Config{
38+
Format: formatCloudWatchLogsSubscriptionFilter,
39+
},
40+
},
41+
}
42+
43+
for _, tt := range tests {
44+
name := strings.ReplaceAll(tt.id.String(), "/", "_")
45+
t.Run(name, func(t *testing.T) {
46+
factory := NewFactory()
47+
cfg := factory.CreateDefaultConfig()
48+
49+
sub, err := cm.Sub(tt.id.String())
50+
require.NoError(t, err)
51+
require.NoError(t, sub.Unmarshal(cfg))
52+
53+
err = xconfmap.Validate(cfg)
54+
if tt.expectedErr != "" {
55+
assert.Error(t, err)
56+
assert.EqualError(t, err, tt.expectedErr)
57+
} else {
58+
assert.NoError(t, err)
59+
assert.Equal(t, tt.expected, cfg)
60+
}
61+
})
62+
}
63+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//go:generate mdatagen metadata.yaml
5+
6+
// Package awslogsencodingextension provides an encoding extension
7+
// for unmarshalling logs produced by various AWS services.
8+
package awslogsencodingextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/awslogsencodingextension"
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package awslogsencodingextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/awslogsencodingextension"
5+
6+
import (
7+
"context"
8+
"fmt"
9+
10+
"go.opentelemetry.io/collector/component"
11+
"go.opentelemetry.io/collector/extension"
12+
"go.opentelemetry.io/collector/pdata/plog"
13+
14+
"github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding"
15+
)
16+
17+
var _ encoding.LogsUnmarshalerExtension = (*encodingExtension)(nil)
18+
19+
type encodingExtension struct {
20+
unmarshaler plog.Unmarshaler
21+
format string
22+
}
23+
24+
func newExtension(cfg *Config, _ extension.Settings) (*encodingExtension, error) {
25+
switch cfg.Format {
26+
case formatCloudWatchLogsSubscriptionFilter:
27+
return &encodingExtension{
28+
unmarshaler: cloudWatchLogsSubscriptionFilterUnmarshaler{},
29+
format: cfg.Format,
30+
}, nil
31+
default:
32+
// Format will have been validated by Config.Validate,
33+
// so we'll only get here if we haven't handled a valid
34+
// format.
35+
return nil, fmt.Errorf("unimplemented format %q", cfg.Format)
36+
}
37+
}
38+
39+
func (*encodingExtension) Start(_ context.Context, _ component.Host) error {
40+
return nil
41+
}
42+
43+
func (*encodingExtension) Shutdown(_ context.Context) error {
44+
return nil
45+
}
46+
47+
func (e *encodingExtension) UnmarshalLogs(record []byte) (plog.Logs, error) {
48+
logs, err := e.unmarshaler.UnmarshalLogs(record)
49+
if err != nil {
50+
return plog.Logs{}, fmt.Errorf("failed to unmarshal logs as '%s' format: %w", e.format, err)
51+
}
52+
return logs, nil
53+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package awslogsencodingextension
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
"go.opentelemetry.io/collector/extension/extensiontest"
12+
)
13+
14+
func TestNew_CloudWatchLogsSubscriptionFilter(t *testing.T) {
15+
e, err := newExtension(&Config{Format: formatCloudWatchLogsSubscriptionFilter}, extensiontest.NewNopSettings(extensiontest.NopType))
16+
require.NoError(t, err)
17+
require.NotNil(t, e)
18+
}
19+
20+
func TestNew_Unimplemented(t *testing.T) {
21+
e, err := newExtension(&Config{Format: "invalid"}, extensiontest.NewNopSettings(extensiontest.NopType))
22+
require.Error(t, err)
23+
require.Nil(t, e)
24+
assert.EqualError(t, err, `unimplemented format "invalid"`)
25+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package awslogsencodingextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/awslogsencodingextension"
5+
6+
import (
7+
"context"
8+
9+
"go.opentelemetry.io/collector/component"
10+
"go.opentelemetry.io/collector/extension"
11+
12+
"github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/awslogsencodingextension/internal/metadata"
13+
)
14+
15+
func NewFactory() extension.Factory {
16+
return extension.NewFactory(
17+
metadata.Type,
18+
createDefaultConfig,
19+
createExtension,
20+
metadata.ExtensionStability,
21+
)
22+
}
23+
24+
func createExtension(_ context.Context, settings extension.Settings, cfg component.Config) (extension.Extension, error) {
25+
return newExtension(cfg.(*Config), settings)
26+
}
27+
28+
func createDefaultConfig() component.Config {
29+
return &Config{}
30+
}

0 commit comments

Comments
 (0)