Skip to content
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

feat(subscriber): introduce wildcard pattern #95

Merged
merged 1 commit into from
Nov 20, 2023
Merged
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
14 changes: 8 additions & 6 deletions apps/subscriber/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,17 @@ Parameters:
LogGroupNamePatterns:
Type: CommaDelimitedList
Description: >-
Comma separated list of patterns. If not empty, the lambda function will
only apply to log groups that have names that match one of the provided
strings based on a case-sensitive substring search.
Default: ''
Comma separated list of patterns.
We will only subscribe to log groups that have names matching one of the
provided strings based on strings based on a case-sensitive substring
search. To subscribe to all log groups, use the wildcard operator *.
Default: '*'
LogGroupNamePrefixes:
Type: CommaDelimitedList
Description: >-
Comma separated list of prefixes. If not empty, the lambda function will
only apply to log groups that start with a provided string.
Comma separated list of prefixes. The lambda function will only apply to
log groups that start with a provided string. To subscribe to all log
groups, use the wildcard operator *.
Default: ''
NumWorkers:
Type: String
Expand Down
17 changes: 16 additions & 1 deletion docs/subscriber.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,22 @@ aws logs describe-log-groups --log-group-name-pattern prod
aws logs describe-log-groups --log-group-name-prefix /aws/lambda
```

If no patterns or prefixes are provided, the lambda function will list all log groups.
To subscribe to all log groups, a wildcard can be provided to either `logGroupNamePatterns` or `logGroupNamePrefixes`. The following input:

```json
{
"discover": {
"logGroupNamePatterns": [ "*" ]
}
}
```

Will trigger a paginated request equivalent to the `awscli` command:

```shell
aws logs describe-log-groups
```


### Response format

Expand Down
28 changes: 19 additions & 9 deletions handler/subscriber/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (c *Config) Validate() error {
}

for _, s := range append(c.LogGroupNamePatterns, c.LogGroupNamePrefixes...) {
if !logGroupNameRe.MatchString(s) {
if !logGroupNameRe.MatchString(s) && s != "*" {
errs = append(errs, fmt.Errorf("%w: %q", ErrInvalidLogGroupName, s))
}
}
Expand All @@ -89,23 +89,33 @@ func (c *Config) Validate() error {
}

func (c *Config) LogGroupFilter() FilterFunc {
var re *regexp.Regexp
filterFunc := func(logGroupName string) bool {
if re != nil {
return re.MatchString(logGroupName)
}
return true
}

var exprs []string

exprs = append(exprs, c.LogGroupNamePatterns...)
for _, pattern := range c.LogGroupNamePatterns {
if pattern == "*" {
return filterFunc
}
exprs = append(exprs, pattern)
}

for _, prefix := range c.LogGroupNamePrefixes {
if prefix == "*" {
return filterFunc
}
exprs = append(exprs, fmt.Sprintf("^%s.*", prefix))
}

var re *regexp.Regexp
if len(exprs) != 0 {
re = regexp.MustCompile(strings.Join(exprs, "|"))
}

return func(logGroupName string) bool {
if re != nil {
return re.MatchString(logGroupName)
}
return true
}
return filterFunc
}
13 changes: 13 additions & 0 deletions handler/subscriber/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func TestConfig(t *testing.T) {
},
ExpectError: subscriber.ErrInvalidLogGroupName,
},

{
Config: subscriber.Config{
CloudWatchLogsClient: &handlertest.CloudWatchLogsClient{},
Expand All @@ -69,6 +70,7 @@ func TestConfig(t *testing.T) {
Config: subscriber.Config{
FilterName: "ok",
CloudWatchLogsClient: &handlertest.CloudWatchLogsClient{},
LogGroupNamePrefixes: []string{"*"},
},
},
}
Expand Down Expand Up @@ -115,6 +117,17 @@ func TestLogFilter(t *testing.T) {
"dev-local": false,
},
},
{
Config: subscriber.Config{
LogGroupNamePatterns: []string{"prod", "*"},
DestinationARN: "hello",
},
Matches: map[string]bool{
"prod-1": true,
"eu-prod": true,
"staging": true,
},
},
}

for i, tc := range testcases {
Expand Down
21 changes: 20 additions & 1 deletion handler/subscriber/discovery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ func TestHandleDiscovery(t *testing.T) {
ExpectJSONResponse string
}{
{
DiscoveryRequest: &subscriber.DiscoveryRequest{},
DiscoveryRequest: &subscriber.DiscoveryRequest{
LogGroupNamePatterns: []*string{aws.String("*")},
},
/* matches:
- /aws/hello
- /aws/ello
Expand All @@ -53,6 +55,23 @@ func TestHandleDiscovery(t *testing.T) {
}
}`,
},
{
DiscoveryRequest: &subscriber.DiscoveryRequest{},
/* matches nothing
*/
ExpectJSONResponse: `{
"discovery": {
"logGroupCount": 0,
"requestCount": 0,
"subscription": {
"deleted": 0,
"updated": 0,
"skipped": 0,
"processed": 0
}
}
}`,
},
{
DiscoveryRequest: &subscriber.DiscoveryRequest{
LogGroupNamePrefixes: []*string{
Expand Down
22 changes: 15 additions & 7 deletions handler/subscriber/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs"
)

Expand Down Expand Up @@ -90,25 +91,32 @@ func (d *DiscoveryRequest) ToDescribeLogInputs() (inputs []*cloudwatchlogs.Descr
}

for _, pattern := range d.LogGroupNamePatterns {
if aws.ToString(pattern) == "*" {
return []*cloudwatchlogs.DescribeLogGroupsInput{
{
Limit: d.Limit,
},
}
}
inputs = append(inputs, &cloudwatchlogs.DescribeLogGroupsInput{
LogGroupNamePattern: pattern,
Limit: d.Limit,
})
}

for _, prefix := range d.LogGroupNamePrefixes {
if aws.ToString(prefix) == "*" {
return []*cloudwatchlogs.DescribeLogGroupsInput{
{
Limit: d.Limit,
},
}
}
inputs = append(inputs, &cloudwatchlogs.DescribeLogGroupsInput{
LogGroupNamePrefix: prefix,
Limit: d.Limit,
})
}

if len(inputs) == 0 {
// We should list all since we were provided with no log groups
// or filters.
inputs = append(inputs, &cloudwatchlogs.DescribeLogGroupsInput{
Limit: d.Limit,
})
}
return inputs
}
1 change: 1 addition & 0 deletions integration/scripts/check_subscriber
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ AWS_REGION=$(echo "$FUNCTION_ARN" | cut -d: -f4)
check_result() {
ERR=$(jq '.StatusCode != 200 or has("FunctionError")' <<<"$1")
if [[ "$ERR" == true ]]; then
cat ${TMPFILE}
echo "$1"
return 1
fi
Expand Down
Loading