Last active
May 31, 2024 01:48
-
-
Save kudoh/ccc1ab931cc2fa636c28f4b3bccca7a2 to your computer and use it in GitHub Desktop.
x-ray custom trace collector sample
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import * as cdk from 'aws-cdk-lib'; | |
| import { Construct } from 'constructs'; | |
| import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'; | |
| import * as iam from 'aws-cdk-lib/aws-iam'; | |
| import { Effect } from 'aws-cdk-lib/aws-iam'; | |
| import * as lambda from 'aws-cdk-lib/aws-lambda'; | |
| import * as apigw from 'aws-cdk-lib/aws-apigatewayv2'; | |
| import { CorsHttpMethod } from 'aws-cdk-lib/aws-apigatewayv2'; | |
| import { RetentionDays } from 'aws-cdk-lib/aws-logs'; | |
| import * as integrations from 'aws-cdk-lib/aws-apigatewayv2-integrations'; | |
| export class CustomXrayStack extends cdk.Stack { | |
| constructor(scope: Construct, id: string, props?: cdk.StackProps) { | |
| super(scope, id, props); | |
| const role = new iam.Role(this, 'GptSlackGatewayLambdaRole', { | |
| roleName: `${this.stackName}-trace-role`, | |
| assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), | |
| managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')], | |
| inlinePolicies: { | |
| XRayPutCustomSegment: new iam.PolicyDocument({ | |
| statements: [new iam.PolicyStatement({ | |
| effect: Effect.ALLOW, | |
| resources: ["*"], | |
| actions: ['xray:PutTraceSegments'] | |
| })] | |
| }), | |
| } | |
| }); | |
| const lambdaFn = new NodejsFunction(this, 'XRayCustomTrace', { | |
| role: role, | |
| functionName: `${this.stackName}-custom-xray-trace`, | |
| description: 'custom xray entry point', | |
| entry: 'lambda/handler.ts', | |
| handler: 'handler', | |
| runtime: lambda.Runtime.NODEJS_20_X, | |
| logRetention: RetentionDays.ONE_WEEK, | |
| }) | |
| const httpApi = new apigw.HttpApi(this, 'HttpApi', { | |
| corsPreflight: { | |
| allowHeaders: ["*"], | |
| allowMethods: [CorsHttpMethod.ANY], | |
| allowOrigins: ["*"] | |
| } | |
| }); | |
| httpApi.addRoutes({ | |
| path: '/', | |
| methods: [apigw.HttpMethod.POST], | |
| integration: new integrations.HttpLambdaIntegration('Integration', lambdaFn) | |
| }); | |
| new cdk.CfnOutput(this, 'HttpApiUrl', { | |
| value: httpApi.url!, | |
| description: 'The url of the HttpApi', | |
| exportName: `${this.stackName}-http-api-url`, | |
| }); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { APIGatewayProxyHandlerV2 } from 'aws-lambda'; | |
| import { PutTraceSegmentsCommand, XRayClient } from '@aws-sdk/client-xray'; | |
| import * as crypto from 'crypto' | |
| type Trace = { | |
| segments: { | |
| [key: string]: { | |
| startTime: number; | |
| endTime: number; | |
| metrics?: { | |
| [key: string]: number | |
| }, | |
| } | |
| } | |
| } | |
| const client = new XRayClient(); | |
| function generateId(len: number = 8) { | |
| return crypto.randomBytes(len).toString('hex'); | |
| } | |
| export const handler: APIGatewayProxyHandlerV2 = async (event) => { | |
| const trace: Trace = JSON.parse(event.body ?? '{}'); | |
| const origin = event.headers['origin'] ?? 'unknown'; | |
| const traceId = `1-${Math.floor(Date.now() / 1000).toString(16)}-${generateId(12)}`; | |
| const min = Math.min(...Object.values(trace.segments).map(v => v.startTime)); | |
| const max = Math.max(...Object.values(trace.segments).map(v => v.endTime)); | |
| const input = { | |
| name: origin, | |
| id: generateId(), | |
| trace_id: traceId, | |
| start_time: min / 1000, | |
| end_time: max / 1000, | |
| subsegments: Object.entries(trace.segments).map(([key, value]) => ({ | |
| id: generateId(), | |
| name: key, | |
| start_time: value.startTime / 1000, | |
| end_time: value.endTime / 1000, | |
| annotations: value.metrics, | |
| })), | |
| annotations: { | |
| userAgent: event.headers['user-agent'] ?? 'unknown' | |
| } | |
| }; | |
| console.log(input) | |
| const command: PutTraceSegmentsCommand = new PutTraceSegmentsCommand({ | |
| TraceSegmentDocuments: [JSON.stringify(input)] | |
| }) | |
| const resp = await client.send(command) | |
| console.log(resp) | |
| return { | |
| statusCode: 204, | |
| } | |
| }; |
Author
Author
{
"$metadata": {
"httpStatusCode": 200,
"requestId": "96ac8d92-9902-4ee9-a932-1f6d33681b51",
"attempts": 1,
"totalRetryDelay": 0
},
"Traces": [
{
"Duration": 8,
"Id": "1-66592a23-c94baf8ea8de377eac545fc9",
"LimitExceeded": false,
"Segments": [
{
"Document": "{\"id\":\"c5cfe1da9b692c3d\",\"name\":\"http://localhost:3000\",\"start_time\":1.717119513474E9,\"trace_id\":\"1-66592a23-c94baf8ea8de377eac545fc9\",\"end_time\":1.717119521474E9,\"annotations\":{\"userAgent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36\"},\"subsegments\":[{\"id\":\"d5ce13de6b80f459\",\"name\":\"/complete\",\"start_time\":1.717119518474E9,\"end_time\":1.717119521474E9},{\"id\":\"8604cc723d83fbcc\",\"name\":\"/option\",\"start_time\":1.717119515474E9,\"end_time\":1.717119516474E9},{\"id\":\"0580cff5bdfa56c3\",\"name\":\"/\",\"start_time\":1.717119513474E9,\"end_time\":1.717119514474E9,\"annotations\":{\"FID\":2.5,\"FCP\":36.0,\"LCP\":36.0,\"TTFB\":18.2}},{\"id\":\"9e189f3297b153c5\",\"name\":\"/input\",\"start_time\":1.717119517474E9,\"end_time\":1.717119517974E9}]}",
"Id": "c5cfe1da9b692c3d"
}
]
}
],
"UnprocessedTraceIds": []
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
{ "$metadata": { "httpStatusCode": 200, "requestId": "e5ddb83d-0066-4a0b-ac6b-5328b5baeea4", "attempts": 1, "totalRetryDelay": 0 }, "ApproximateTime": "2024-05-31T01:00:00.000Z", "NextToken": "htu98DIpoYx+ky8XKeC/ZdjpVkN4IkVwlqrz6JUETWQyT+3FKWwVnCtdtv9RQ16X", "TraceSummaries": [ { "Annotations": { "FCP": [ { "AnnotationValue": { "NumberValue": 36 } } ], "FID": [ { "AnnotationValue": { "NumberValue": 2.5 } } ], "LCP": [ { "AnnotationValue": { "NumberValue": 36 } } ], "TTFB": [ { "AnnotationValue": { "NumberValue": 18.2 } } ], "userAgent": [ { "AnnotationValue": { "StringValue": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36" } } ] }, "AvailabilityZones": [], "Duration": 8, "EntryPoint": { "Name": "http://localhost:3000", "Names": [ "http://localhost:3000" ] }, "ErrorRootCauses": [], "FaultRootCauses": [], "HasError": false, "HasFault": false, "HasThrottle": false, "Http": {}, "Id": "1-66592a25-10ed50d4739c50e344a501a2", "InstanceIds": [], "IsPartial": false, "ResourceARNs": [], "ResponseTime": 8, "ResponseTimeRootCauses": [], "Revision": 1, "ServiceIds": [ { "Name": "http://localhost:3000", "Names": [ "http://localhost:3000" ], "Type": "client" }, { "Name": "http://localhost:3000", "Names": [ "http://localhost:3000" ] } ], "StartTime": "2024-05-31T01:38:35.000Z", "Users": [] }, { "Annotations": { "FCP": [ { "AnnotationValue": { "NumberValue": 36 } } ], "FID": [ { "AnnotationValue": { "NumberValue": 2.5 } } ], "LCP": [ { "AnnotationValue": { "NumberValue": 36 } } ], "TTFB": [ { "AnnotationValue": { "NumberValue": 18.2 } } ], "userAgent": [ { "AnnotationValue": { "StringValue": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36" } } ] }, "AvailabilityZones": [], "Duration": 8, "EntryPoint": { "Name": "http://localhost:3000", "Names": [ "http://localhost:3000" ] }, "ErrorRootCauses": [], "FaultRootCauses": [], "HasError": false, "HasFault": false, "HasThrottle": false, "Http": {}, "Id": "1-66592a24-b8701a4543dd24deecc8404a", "InstanceIds": [], "IsPartial": false, "ResourceARNs": [], "ResponseTime": 8, "ResponseTimeRootCauses": [], "Revision": 1, "ServiceIds": [ { "Name": "http://localhost:3000", "Names": [ "http://localhost:3000" ], "Type": "client" }, { "Name": "http://localhost:3000", "Names": [ "http://localhost:3000" ] } ], "StartTime": "2024-05-31T01:38:34.000Z", "Users": [] }, { "Annotations": { "FCP": [ { "AnnotationValue": { "NumberValue": 36 } } ], "FID": [ { "AnnotationValue": { "NumberValue": 2.5 } } ], "LCP": [ { "AnnotationValue": { "NumberValue": 36 } } ], "TTFB": [ { "AnnotationValue": { "NumberValue": 18.2 } } ], "userAgent": [ { "AnnotationValue": { "StringValue": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36" } } ] }, "AvailabilityZones": [], "Duration": 8, "EntryPoint": { "Name": "http://localhost:3000", "Names": [ "http://localhost:3000" ] }, "ErrorRootCauses": [], "FaultRootCauses": [], "HasError": false, "HasFault": false, "HasThrottle": false, "Http": {}, "Id": "1-66592a23-c94baf8ea8de377eac545fc9", "InstanceIds": [], "IsPartial": false, "ResourceARNs": [], "ResponseTime": 8, "ResponseTimeRootCauses": [], "Revision": 1, "ServiceIds": [ { "Name": "http://localhost:3000", "Names": [ "http://localhost:3000" ], "Type": "client" }, { "Name": "http://localhost:3000", "Names": [ "http://localhost:3000" ] } ], "StartTime": "2024-05-31T01:38:33.000Z", "Users": [] } ], "TracesProcessedCount": 20 }