Skip to content

Commit e1f3341

Browse files
authored
Merge pull request #56 from 1Password/amanda/events-api-lambda
moving the golang lamba here
2 parents 9d28b21 + 8d37a40 commit e1f3341

File tree

6 files changed

+381
-0
lines changed

6 files changed

+381
-0
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# 1Password Events API Base Golang Lambda Script
2+
3+
This folder contains the necessary components for getting starting piping events from the 1Password Event API into Cloudwatch Logs using a Lambda. If you like the region and the names of variables, you can use the AWS UI to create a few things and then upload bootstrap.zip as is.
4+
5+
If you need to make changes to the region or other parts of the script, you will need to recompile the script. See "[Build From Code](#build-from-code)" for guidance on recompiling.
6+
7+
## Resources
8+
9+
[Events API Documentation](https://developer.1password.com/docs/events-api/)
10+
11+
## Using as-is
12+
13+
1. Setup the Events Reporting integration in 1Password using [these instructions](https://support.1password.com/events-reporting/#step-1-set-up-an-events-reporting-integration) and selecting `Other`. The only event types in the current script are Sign-In events.
14+
2. Log into the us-east-1 region in AWS and create the following:
15+
- In AWS Secrets Manager, create a secret called `op-events-api-token`
16+
- Secret Type: Other type of secret
17+
- Key/value pairs: Plaintext -> paste in the bearer token
18+
- Everything else can be left as default
19+
- In AWS Systems Manager -> Parameter Store, create a secret called `op-events-api-cursor`
20+
- Tier: Standard
21+
- Type: String
22+
- Data Type: text
23+
- Value: first_run
24+
- In AWS CloudWatch, create a log group called `op-events-api-signins`, leaving everything else as default. Add a log stream to this log group call `op-events-api-signins-stream`
25+
- In AWS Lambda, create a new function called `op-events-api-signins-lambda`
26+
- Runtime: Amazon Linux 2
27+
- Architecture: arm64
28+
- Create a new role with basic Lambda permissions
29+
3. After the lambda is created, go to AWS IAM -> Roles and click on `op-events-api-signins-lambda-role-#####` (###### just represents some random characters) and edit the json under the policy `AWSLambdaBasicExecutionRole-#####` to be:
30+
31+
```json
32+
{
33+
"Version": "2012-10-17",
34+
"Statement": [
35+
{
36+
"Effect": "Allow",
37+
"Action": [
38+
"logs:CreateLogGroup",
39+
"secretsmanager:DescribeSecret",
40+
"secretsmanager:GetSecretValue",
41+
"ssm:GetParameter",
42+
"ssm:PutParameter"
43+
],
44+
"Resource": "arn:aws:logs:us-east-1:<account>:*"
45+
},
46+
{
47+
"Effect": "Allow",
48+
"Action": [
49+
"logs:CreateLogStream",
50+
"logs:PutLogEvents",
51+
"secretsmanager:DescribeSecret",
52+
"secretsmanager:GetSecretValue",
53+
"ssm:GetParameter",
54+
"ssm:PutParameter"
55+
],
56+
"Resource": [
57+
"arn:aws:logs:us-east-1:<account>:log-group:/aws/lambda/op-events-api-signins-lambda:*"
58+
]
59+
}
60+
]
61+
}
62+
```
63+
64+
and then Add permissions -> attach policies, then add the policies `AmazonSSMFullAccess` and `SecretsManagerReadWrite`
65+
4. Return to the lambda function and on the right, select Upload from -> zip file and then navigate to and find bootstrap.zip from this folder.
66+
5. Navigate to test and then click the orange `Test` button, and you should get a success, and when you check the cloudwatch group and stream, there should be a new entry.
67+
6. Add a trigger for how frequently you would like this to run. For example, EventBridge, new rule with expression `rate(10 minutes)`
68+
69+
## Notes
70+
71+
- This is very much still in beta and has not been tested extensively
72+
- This is not optimized yet - it's a first pass to get it working, there are definitely smarter ways to do this
73+
- This starts with the last 24 hours of data, and does not currently load any events before then
74+
75+
76+
## Build from code
77+
If you need to make changes to the script to fit your environment or specifications, you will need to recompile the script. Once you've made your changes, use the following command to compile. Once compiled, you may follow the [deployment directions](#using-as-is), using the newly-compiled boostrap.zip.
78+
79+
```bash
80+
GOOS=linux GOARCH=arm64 go build -tags lambda.norpc -o bootstrap main.go && zip bootstrap.zip bootstrap
81+
```
10 MB
Binary file not shown.
5.21 MB
Binary file not shown.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module amanda-lambda
2+
3+
go 1.21.6
4+
5+
require (
6+
github.com/aws/aws-lambda-go v1.46.0
7+
github.com/aws/aws-sdk-go-v2 v1.24.1
8+
github.com/aws/aws-sdk-go-v2/config v1.26.6
9+
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.2
10+
)
11+
12+
require (
13+
github.com/aws/aws-sdk-go v1.50.15 // indirect
14+
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect
15+
github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect
16+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect
17+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect
18+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect
19+
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect
20+
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.32.0 // indirect
21+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect
22+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect
23+
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 // indirect
24+
github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect
25+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect
26+
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect
27+
github.com/aws/smithy-go v1.19.0 // indirect
28+
github.com/davecgh/go-spew v1.1.1 // indirect
29+
github.com/jmespath/go-jmespath v0.4.0 // indirect
30+
)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
github.com/aws/aws-lambda-go v1.46.0 h1:UWVnvh2h2gecOlFhHQfIPQcD8pL/f7pVCutmFl+oXU8=
2+
github.com/aws/aws-lambda-go v1.46.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A=
3+
github.com/aws/aws-sdk-go v1.50.15 h1:wEMnPfEQQFaoIJwuO18zq/vtG4Ft7NxQ3r9xlEi/8zg=
4+
github.com/aws/aws-sdk-go v1.50.15/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
5+
github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU=
6+
github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4=
7+
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs=
8+
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4/go.mod h1:usURWEKSNNAcAZuzRn/9ZYPT8aZQkR7xcCtunK/LkJo=
9+
github.com/aws/aws-sdk-go-v2/config v1.26.6 h1:Z/7w9bUqlRI0FFQpetVuFYEsjzE3h7fpU6HuGmfPL/o=
10+
github.com/aws/aws-sdk-go-v2/config v1.26.6/go.mod h1:uKU6cnDmYCvJ+pxO9S4cWDb2yWWIH5hra+32hVh1MI4=
11+
github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8=
12+
github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0=
13+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8=
14+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y=
15+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4=
16+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4=
17+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw=
18+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw=
19+
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 h1:n3GDfwqF2tzEkXlv5cuy4iy7LpKDtqDMcNLfZDu9rls=
20+
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY=
21+
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.32.0 h1:VdKYfVPIDzmfSQk5gOQ5uueKiuKMkJuB/KOXmQ9Ytag=
22+
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.32.0/go.mod h1:jZNaJEtn9TLi3pfxycLz79HVkKxP8ZdYm92iaNFgBsA=
23+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw=
24+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ=
25+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4=
26+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino=
27+
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.2 h1:A5sGOT/mukuU+4At1vkSIWAN8tPwPCoYZBp7aruR540=
28+
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.2/go.mod h1:qutL00aW8GSo2D0I6UEOqMvRS3ZyuBrOC1BLe5D2jPc=
29+
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 h1:a8HvP/+ew3tKwSXqL3BCSjiuicr+XTU2eFYeogV9GJE=
30+
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7/go.mod h1:Q7XIWsMo0JcMpI/6TGD6XXcXcV1DbTj6e9BKNntIMIM=
31+
github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow=
32+
github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM=
33+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA=
34+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8=
35+
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0=
36+
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U=
37+
github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM=
38+
github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE=
39+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
40+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
41+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
42+
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
43+
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
44+
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
45+
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
46+
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
47+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
48+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
49+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
50+
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
51+
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
52+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
53+
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
54+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
55+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
"io"
8+
"log"
9+
"net/http"
10+
"time"
11+
12+
"context"
13+
14+
"github.com/aws/aws-lambda-go/lambda"
15+
"github.com/aws/aws-sdk-go-v2/aws"
16+
"github.com/aws/aws-sdk-go-v2/config"
17+
"github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs"
18+
"github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs/types"
19+
"github.com/aws/aws-sdk-go-v2/service/secretsmanager"
20+
"github.com/aws/aws-sdk-go-v2/service/ssm"
21+
)
22+
23+
type Signins struct {
24+
Cursor string `json:"cursor"`
25+
Has_more bool `json:"has_more"`
26+
Items []Item `json:"items"`
27+
}
28+
29+
type TargetUser struct {
30+
UUID string `json:"uuid"`
31+
Name string `json:"name"`
32+
Email string `json:"email"`
33+
}
34+
35+
type Client struct {
36+
AppName string `json:"app_name"`
37+
AppVersion string `json:"app_version"`
38+
PlatformName string `json:"platform_name"`
39+
PlatformVersion string `json:"platform_version"`
40+
OSName string `json:"os_name"`
41+
OSVersion string `json:"os_version"`
42+
IPAddress string `json:"ip_address"`
43+
}
44+
45+
type Location struct {
46+
Country string `json:"country"`
47+
Region string `json:"region"`
48+
City string `json:"city"`
49+
Latitude float64 `json:"latitude"`
50+
Longitude float64 `json:"longitude"`
51+
}
52+
53+
type Item struct {
54+
UUID string `json:"uuid"`
55+
SessionUUID string `json:"session_uuid"`
56+
Timestamp time.Time `json:"timestamp"`
57+
Country string `json:"country"`
58+
Category string `json:"category"`
59+
Type string `json:"type"`
60+
Details string `json:"details"`
61+
TargetUser TargetUser `json:"target_user"`
62+
Client Client `json:"client"`
63+
Location Location `json:"location"`
64+
}
65+
66+
var (
67+
eventAPIurl string = "https://events.1password.com"
68+
region string = "us-east-1"
69+
secretName string = "op-events-api-token"
70+
parameterName string = "op-events-api-cursor"
71+
cloudwatchLogGroup string = "op-events-api-signins"
72+
cloudwatchStream string = "op-events-api-signins-stream"
73+
)
74+
75+
func main() {
76+
lambda.Start(getSignInEvents)
77+
}
78+
79+
// Retrieves data from the sign-in events endpoint.
80+
// Depending on your implementation you may want to create functions for each of the three endpoints,
81+
// or refactor this function to accept an endpoint and any other required properties, calling it once for each of the three endpoints.
82+
func getSignInEvents() {
83+
api_token := loadToken()
84+
start_time := time.Now().AddDate(0, 0, -1)
85+
86+
currCursor := getCursor()
87+
88+
var payload []byte
89+
if currCursor == "first_run" || currCursor == "" {
90+
payload = []byte(fmt.Sprintf(`{
91+
"limit": 1000,
92+
"start_time": "%s"
93+
}`, start_time.Format(time.RFC3339)))
94+
} else {
95+
payload = []byte(fmt.Sprintf(`{
96+
"cursor": "%s"
97+
}`, currCursor))
98+
}
99+
100+
client := &http.Client{}
101+
102+
signinsRequest, _ := http.NewRequest("POST", fmt.Sprintf("%s/api/v1/signinattempts", eventAPIurl), bytes.NewBuffer(payload))
103+
signinsRequest.Header.Set("Content-Type", "application/json")
104+
signinsRequest.Header.Set("Authorization", "Bearer "+api_token)
105+
signinsResponse, signinsError := client.Do(signinsRequest)
106+
if signinsError != nil {
107+
panic(signinsError)
108+
}
109+
defer signinsResponse.Body.Close()
110+
signinsBody, _ := io.ReadAll(signinsResponse.Body)
111+
112+
var results Signins
113+
json.Unmarshal(signinsBody, &results)
114+
115+
if len(results.Items) != 0 {
116+
writeLogs(results.Items)
117+
setCursor(results.Cursor)
118+
}
119+
120+
if results.Has_more {
121+
getSignInEvents()
122+
}
123+
}
124+
125+
func loadConfig() aws.Config {
126+
config, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(region))
127+
if err != nil {
128+
log.Fatal(err)
129+
}
130+
131+
return config
132+
}
133+
134+
func loadToken() string {
135+
// Create Secrets Manager client
136+
svc := secretsmanager.NewFromConfig(loadConfig())
137+
138+
input := &secretsmanager.GetSecretValueInput{
139+
SecretId: aws.String(secretName),
140+
VersionStage: aws.String("AWSCURRENT"), // VersionStage defaults to AWSCURRENT if unspecified
141+
}
142+
143+
result, err := svc.GetSecretValue(context.TODO(), input)
144+
if err != nil {
145+
// For a list of exceptions thrown, see
146+
// https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
147+
log.Fatal(err.Error())
148+
}
149+
150+
// Decrypts secret using the associated KMS key.
151+
return *result.SecretString
152+
153+
}
154+
155+
// Get API cursor from ParameterStore. Could be refactored to take an endpoint as
156+
// an argument and fetch the corresponding cursor.
157+
func getCursor() string {
158+
paramInput := ssm.GetParameterInput{
159+
Name: aws.String(parameterName),
160+
}
161+
paramStore := ssm.NewFromConfig(loadConfig())
162+
output, err := paramStore.GetParameter(context.TODO(), &paramInput)
163+
if err != nil {
164+
log.Print(err)
165+
return ""
166+
}
167+
168+
return *output.Parameter.Value
169+
}
170+
171+
// Writes new cursor to parameter store. Could be refactored to take an endpoint as
172+
// an argument and fetch the corresponding cursor.
173+
func setCursor(cursor string) {
174+
paramInput := ssm.PutParameterInput{
175+
Name: aws.String(parameterName),
176+
Value: &cursor,
177+
Overwrite: aws.Bool(true),
178+
}
179+
paramStore := ssm.NewFromConfig(loadConfig())
180+
181+
paramStore.PutParameter(context.TODO(), &paramInput)
182+
}
183+
184+
// Write logs to destination. In this case CloudWatch, but would require refactoring
185+
// for your specific implementation and destination.
186+
func writeLogs(logItems []Item) {
187+
// Create a CloudWatchLogs client with additional configuration
188+
svc := cloudwatchlogs.NewFromConfig(loadConfig())
189+
190+
// Each array of InputLogEvent's needs to be within a 24-hour window
191+
// In theory, this is only an issue on first call
192+
var events []types.InputLogEvent
193+
for _, item := range logItems {
194+
timestamp := item.Timestamp.UnixMilli()
195+
itemByte, _ := json.Marshal(item)
196+
itemString := string(itemByte)
197+
event := types.InputLogEvent{
198+
Message: &itemString,
199+
Timestamp: &timestamp,
200+
}
201+
202+
events = append(events, event)
203+
}
204+
205+
logEvent := cloudwatchlogs.PutLogEventsInput{
206+
LogEvents: events,
207+
LogGroupName: &cloudwatchLogGroup,
208+
LogStreamName: &cloudwatchStream,
209+
}
210+
211+
_, err := svc.PutLogEvents(context.TODO(), &logEvent)
212+
213+
// log.Println("writeLogs error:")
214+
log.Println(err)
215+
}

0 commit comments

Comments
 (0)