-
Notifications
You must be signed in to change notification settings - Fork 559
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
Is there a cloudwatch events example. #51
Comments
The details are stored in a From the documentation it looks like json.Unmarshal(some_json_raw_message, &some_struct) Let me know if that helps |
I would also like some docs on this. I simply want to export the event as json. In particular is there a way to get the CloudWatch event into a |
@btsteve Here's my example decode of the CloudWatch Event that I got working after some struggling
Works for getting CloudWatch events out to a generic http endpoint. |
I've been grappling with there being almost zero docs on this too, so here's an example of unmarshaling the // CloudWatchRdsSnapshotEventDetail represnts an AWS CloudWatch event triggered
// by a new RDS snapshot being created.
type CloudWatchRdsSnapshotEventDetail struct {
// "EventCategories": [
// "creation"
// ],
// "SourceType": "SNAPSHOT",
// "SourceArn": "arn:aws:rds:us-east-1:123456789012:db:rds:mysql-instance-2018-10-06-12-24",
// "Date": "2018-10-06T12:26:13.882Z",
// "SourceIdentifier": "rds:mysql-instance-2018-10-06-12-24",
// "Message": "Automated snapshot created"
EventCategories []string `json:"EventCategories`
SourceType string `json:"SourceType"`
SourceArn string `json:"SourceArn"`
Date string `json:"Date"`
SourceIdentifier string `json:"SourceIdentifier"`
Message string `json:"Message"`
} You can use it like this: var snapshotEventDetail CloudWatchRdsSnapshotEventDetail
json.Unmarshal(snapshotCloudwatchEvent.Detail, &snapshotEventDetail) ...where There's nothing crazy happening here, it's just standard Go JSON unmarshalling into a struct type. It looks like you'll need to create your own structs for messages for now, as far as I can see anyway. Hope this helps. |
Hey guys! I'm in the process of converting my python over to Go and was struggling with this a bit myself :( Considering the CloudWatchEvent.Details field doesn't cover all of the events one could possibly handle/ unmarshall, you may want to consider using a map[string]interface{} to unmarshall the event details. This makes it easy to capture the elements from the resulting map that you may need as a local var. Here's my example for capturing details for an AWS API Event Via Cloud Trail and displaying them to STDOUT. P.S @xiy has the best method for unmarshalling structured json, but some of these events are huge and change based on certain parameters, ergo my current usage of type map. Maybe there is a better way? You'd also have to be mindful of the types you are pulling from the map, so the nested events could be of type Struct. This is a helpful tool:https://mholt.github.io/json-to-go/ Update: I just wound up making a custom struct for the elements I needed. Here is my updated code: And I totally agree, having more concrete examples would help the newbies like myself 👍 /**
This function listens for a cloudWatch event that filters for AWS API calls via
CloudTrail. Moreover, it appends a series of reference vars and instance IDs to a dictionary in order to tag ec2
instances with a predefined set of key pair values.
Note: In order to attain the proper event level details you'll need to log the
event level metadata to the cloudwatch logs and capture the json for testing
purposes. e.g.
You'll also need to build your goPackage and compress the executable in the working package directory
This command will produce a binary file called "main" -> GOOS=linux GOARCH=amd64 go build -o main autoTagEc2Instances.go
Hey guys, was struggling with this a bit as well considering the CloudWatchEvent Struct type doesn't cover all of the events one could possibly handle/ unmarshall via lambda. While @xiy has the best method here, you may want to consider using a map of type map[string]interface{} to unmarshall the details. This also makes it easy to capture the elements from the resulting map that you may need as a local var. Here's my example for capturing details for an AWS API Event Via Cloud Trail:
To check the event level from cloudWatch logs navigate to cloudWatch, Logs,
the appropriate log group, e.g./aws/lambda/EC2-AutoTag-EC2..., and the verison
of the lambda function you are testing
*/
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/patalwell/awsLambdaGoLangAutoTagEc2/CloudTrailApiEvent"
"log"
)
/*
Sample Event Type we need to unmarshall
type CloudWatchEvent struct {
Version string `json:"version"`
ID string `json:"id"`
DetailType string `json:"detail-type"`
Source string `json:"source"`
AccountID string `json:"account"`
Time time.Time `json:"time"`
Region string `json:"region"`
Resources []string `json:"resources"`
Detail json.RawMessage `json:"detail"`
}
*/
var eventDetail map[string]interface{}
var eventDetails CustomAwsLambdaEvent.CloudWatchEventDetails
//HandleRequest is a required function for Lambda and GoLang
func HandleRequest(ctx context.Context, jsonEvent events.CloudWatchEvent ) {
//Unmarshall the CloudWatchEvent Struct Details
err := json.Unmarshal(jsonEvent.Detail, &eventDetails)
if err != nil {
log.Fatal("Could not unmarshal scheduled event: ", err)
fmt.Println("Could not unmarshal scheduled event: ", err)
}
outputJSON, err := json.Marshal(eventDetails)
if err != nil {
log.Fatal("Could not unmarshal scheduled event: ", err)
fmt.Println("Could not unmarshal scheduled event: ", err)
}
fmt.Println("This is the JSON for event details", string(outputJSON))
version := jsonEvent.Version
id := jsonEvent.ID
detailType := jsonEvent.DetailType
source := jsonEvent.Source
accountId := jsonEvent.AccountID
eventTime := jsonEvent.Time
region := jsonEvent.Region
resources := jsonEvent.Resources
//eventname = detail['eventName']
eventName := eventDetails.EventName
//arn = detail['userIdentity']['arn']
arn := eventDetails.UserIdentity.Arn
//principal = detail['userIdentity']['principalId']
principal := eventDetails.UserIdentity.PrincipalID
//userType = detail['userIdentity']['type']
userType := eventDetails.UserIdentity.Type
//user = detail['userIdentity']['userName']
user := eventDetails.UserIdentity.UserName
//date = detail['eventTime']
date := eventDetails.EventTime
//items = detail['responseElements']['instancesSet']['items'][0]['instanceId']
instanceId := eventDetails.ResponseElements.InstancesSet.Items[0].InstanceID
fmt.Println("This is the version: ",version)
fmt.Println("This is the id: ",id)
fmt.Println("This is the detailType: ",detailType)
fmt.Println("This is the Source: ",source)
fmt.Println("This is the accountId: ",accountId)
fmt.Println("This is the eventTime: ", eventTime)
fmt.Println("This is the region: ",region)
fmt.Println("This is the resource: ",resources)
fmt.Println("Here is the eventName: ", eventName)
fmt.Println("Here is the date: ", date)
fmt.Println("Here is the arn: ", arn)
fmt.Println("Here is the principalId: ", principal)
fmt.Println("Here is the userType: ", userType)
fmt.Println("Here is the user: ", user)
fmt.Println("Here is the instanceId: ", instanceId)
}
func main() {
lambda.Start(HandleRequest)
} |
Wound up making my own Struct for the event in question, which is quite the chore without https://mholt.github.io/json-to-go/. Again, the map[string]interface{} works but will break for nested Types...e.g. Time, Date, etc You can trim the struct to match the fields you need: @xiy has the best answer IMO, the map[string]interface{} is ok for testing. package CustomAwsLambdaEvent
import "time"
type CloudWatchEventDetails struct {
EventVersion string `json:"eventVersion"`
EventID string `json:"eventID"`
EventTime time.Time `json:"eventTime"`
EventType string `json:"eventType"`
ResponseElements struct {
OwnerID string `json:"ownerId"`
InstancesSet struct {
Items []struct {
InstanceID string `json:"instanceId"`
} `json:"items"`
} `json:"instancesSet"`
} `json:"responseElements"`
AwsRegion string `json:"awsRegion"`
EventName string `json:"eventName"`
UserIdentity struct {
UserName string `json:"userName"`
PrincipalID string `json:"principalId"`
AccessKeyID string `json:"accessKeyId"`
InvokedBy string `json:"invokedBy"`
Type string `json:"type"`
Arn string `json:"arn"`
AccountID string `json:"accountId"`
} `json:"userIdentity"`
EventSource string `json:"eventSource"`
} |
Here is an EventsDetails struct I built for monitoring MediaConvert events in CloudWatch. It contains entries for all (most) Status events posted by AWS Elemental Media Convert. type MediaConvertEventDetail struct {
Timestamp int
AccountId string
Queue string
JobId string
Status string
ErrorCode int
ErrorMessage string
FramesDecoded int
JobProgress struct {
PhaseProgress struct {
PROBING struct {
Status string
PercentComplete int
}
TRANSCODING struct {
Status string
PercentComplete int
}
UPLOADING struct {
Status string
PercentComplete int
}
}
JobPercentComplete int
CurrentPhase string
RetryCount int
}
OutputGroupDetails []struct {
OutputDetails []struct {
OutputFilePaths []string
DurationInMs int
VideoDetails struct {
WidthInPx int
HeightInPx int
}
}
PlaylistFilePaths []string
Type string
}
}
func Handler(ctx context.Context, event events.CloudWatchEvent) {
var eventDetails MediaConvertEventDetail
fmt.Printf("The string : %s\n", string(event.Detail[:]))
_ = json.Unmarshal(event.Detail, &eventDetails)
switch eventDetails.Status {
case "STATUS_UPDATE":
fmt.Printf("Updating, %d percent complete", eventDetails.JobProgress.JobPercentComplete)
break
case "PROGRESSING":
fmt.Printf("Starting up job id %s\n", eventDetails.JobId)
break
case "ERROR":
fmt.Printf("Error! %s\n", eventDetails.ErrorMessage)
break
case "COMPLETE":
fmt.Printf("Complete: %d output file paths\n", len(eventDetails.OutputGroupDetails))
break
}
}
func main() {
lambda.Start(Handler)
} |
None of the above works for me. I had created a CloudWatch Event Rule. Here is the output from CloudWatch Log Group for my Lambda function:
At a loss since this contradicts the documentation here Here is my code:
|
@HeathNaylor it looks like you have an empty payload or you aren't deserializing the event which is a byte array. What does the details portion of your event look like? You can grab sample data from CloudTrail API logs OR attempt to find examples online. I would suggest going to look at the event in question in the CloudTrail logs so you have something to test against. Here's an example of what I mean by needing details: {
"version": "0",
"id": "6a7e8feb-b491-4cf7-a9f1-bf3703467718",
"detail-type": "EC2 Instance State-change Notification",
"source": "aws.ec2",
"account": "111122223333",
"time": "2017-12-22T18:43:48Z",
"region": "us-west-1",
"resources": [
"arn:aws:ec2:us-west-1:123456789012:instance/ i-1234567890abcdef0"
],
"detail": {
"instance-id": " i-1234567890abcdef0",
"state": "terminated"
}
}
It seems like your event or test payload is using something like this or you simply aren't deserializing the event when you go to handle the request.
event.Detail is typically serialized as a byte array; so you'll more than likely need to deserialize the event.Detail using the Json SERDE lib or defaulting to a map[string]interface{}. I've replicated this on my end with : |
I ran into the same issue as @HeathNaylor In my case, I wanted CloudWatch Events to pass constant JSON to lambda as input as shown below: Turns out, when Handling it is simple. Either of these can be used: type Request {
CountryISO string `json:"country_iso"`
}
func handleRequest(ctx context.Context, req Request) {
} or func handleRequest(ctx context.Context, b json.RawMessage) {
// json.RawMessage is basically []byte i.e raw json
// that can be unmarshalled
// json.RawMessage can be used to check what's being passed
} |
If you go to eventbridge schema registry and select schema on the left hand side menu, there is a library of schemas. You can download code bindings for them (but not in go). However, if you download the openapi spec there are tools online eg. https://github.com/OpenAPITools/openapi-generator that will generate the structures you require in go. |
I see the cloudwatch_events.go file in the repo but there is no example for this. I have tried using the type but the import does not seem to work. My problem seems to be getting the details of the message.
Thanks, I am new to go so it could be my problem, but I think I am using thing correctly.
My use case is I am trying to use a cloudwatch_event to trigger my lambda.
The text was updated successfully, but these errors were encountered: