Introduction#
- Trace example
- Understanding segment processing time
- Use trace id to track and query
Lambda#
Let's crate a lambda function in CloudFormation.
AWSTemplateFormatVersion: 2010-09-09Description: 'a lambda function'Resources:# Create an IAM Role for lambda functionLambdaExecutionRole:Type: 'AWS::IAM::Role'Properties:AssumeRolePolicyDocument:Version: 2012-10-17Statement:- Effect: AllowPrincipal:Service:- lambda.amazonaws.comAction:- 'sts:AssumeRole'Path: /demo/logaccess/Policies:- PolicyName: rootPolicyDocument:Version: 2012-10-17Statement:- Effect: AllowAction:- 'logs:CreateLogGroup'- 'logs:CreateLogStream'- 'logs:PutLogEvents'Resource: 'arn:aws:logs:*:*:*'- Effect: AllowAction:- 'bedrock:InvokeModel'Resource: !Sub arn:${AWS::Partition}:bedrock:${AWS::Region}::foundation-model/*# Create a Lambda functionLambdaFunction:Type: AWS::Lambda::FunctionProperties:Handler: 'index.handler'Role: !GetAtt LambdaExecutionRole.Arn# Environment variablesEnvironment:Variables:REGION: !Sub ${AWS::Region}Code:ZipFile: |import jsonimport timedef handler(event, context):# heavy processing job# time.sleep(10)# raise exception to test api code 500if 1==2:raise Exception('Malformed input ...')# returnreturn {'statusCode': 200,'body': json.dumps('Hello from Lambda!')}Runtime: 'python3.10'Timeout: 30Outputs:LambdaFunctionArn:Value: !GetAtt LambdaFunction.ArnExport:Name:Fn::Sub: ${AWS::StackName}-LambdaFunctionArn
API Gateway#
Let's create an api gateway.
AWSTemplateFormatVersion: '2010-09-09'Description: Create an rest apiParameters:BedrockLambdaStackName:Type: StringDefault: 'cfn-lambda-bedrock'ApiName:Type: StringDefault: 'rest-api-bedrock'Resources:# Create clodwatch log role for api gatewayApiGatewayCloudWatchRole:Type: 'AWS::IAM::Role'Properties:AssumeRolePolicyDocument:Version: '2012-10-17'Statement:- Effect: 'Allow'Principal:Service:- 'apigateway.amazonaws.com'Action:- 'sts:AssumeRole'Path: '/'Policies:- PolicyName: 'root'PolicyDocument:Version: '2012-10-17'Statement:- Effect: 'Allow'Action:- 'logs:CreateLogGroup'- 'logs:CreateLogStream'- 'logs:DescribeLogGroups'- 'logs:DescribeLogStreams'- 'logs:PutLogEvents'- 'logs:GetLogEvents'- 'logs:FilterLogEvents'Resource: '*'# Create an IAM Role for api gateway to invoke lambda functionsApiGatewayLambdaRole:Type: 'AWS::IAM::Role'Properties:AssumeRolePolicyDocument:Version: 2012-10-17Statement:- Effect: AllowPrincipal:Service:- apigateway.amazonaws.comAction:- 'sts:AssumeRole'Path: /Policies:- PolicyName: rootPolicyDocument:Version: 2012-10-17Statement:- Effect: AllowAction: 'lambda:*'Resource: '*'# Create a rest apiRestApi:Type: AWS::ApiGateway::RestApiProperties:Name: !Ref ApiNameDescription: 'rest api bedrock'EndpointConfiguration:Types:- REGIONAL# Create a resource named bedrockBedrockResource:Type: AWS::ApiGateway::ResourceProperties:RestApiId: !Ref RestApiParentId: !GetAtt RestApi.RootResourceIdPathPart: 'bedrock'# Create a GET method for the bedrock resource and integrate with a Lambda functionGetBedrockMethod:Type: AWS::ApiGateway::MethodProperties:RestApiId: !Ref RestApiResourceId: !Ref BedrockResourceHttpMethod: GETAuthorizationType: NONEMethodResponses:- StatusCode: 200ResponseParameters:method.response.header.Access-Control-Allow-Origin: truemethod.response.header.Access-Control-Allow-Methods: truemethod.response.header.Access-Control-Allow-Headers: trueResponseModels:application/json: Empty- StatusCode: 500ResponseParameters:method.response.header.Access-Control-Allow-Origin: truemethod.response.header.Access-Control-Allow-Methods: truemethod.response.header.Access-Control-Allow-Headers: trueResponseModels:application/json: EmptyIntegration:Type: AWS_PROXY# get role arn from above created roleCredentials: !GetAtt ApiGatewayLambdaRole.ArnIntegrationResponses:- StatusCode: 200ResponseParameters:method.response.header.Access-Control-Allow-Origin: "'*'"method.response.header.Access-Control-Allow-Methods: "'GET,POST,PUT,DELETE,OPTIONS'"method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"- StatusCode: 500# http status regexSelectionPattern: 'Malformed.*'ResponseParameters:method.response.header.Access-Control-Allow-Origin: "'*'"method.response.header.Access-Control-Allow-Methods: "'GET,POST,PUT,DELETE,OPTIONS'"method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"IntegrationHttpMethod: POSTUri: !Sub- arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations- lambdaArn: !ImportValueFn::Sub: ${BedrockLambdaStackName}-LambdaFunctionArn# Create deployment stage named ProdDeployment:Type: AWS::ApiGateway::DeploymentDependsOn:- GetBedrockMethodProperties:RestApiId: !Ref RestApiStageName: Prod
Segment Time Processing#
Trace ID#
Send a request from browser or using curl
curl - v https://96wd9grlbd.execute-api.us-west-2.amazonaws.com/Prod/bedrock?prompt=%22how%20to%20cook%20chicken?%22
In the header of received response, tehre is a trace id
'X-Amzn-Trace-Id': 'Root=1-6660d328-424386874f29954758acde95'
CloudWatch Log Insights#
Select 2 log groups:
- Lambda log group: /aws/lambda/cfn-lambda-bedrock-LambdaFunction-x3nilLA08KXQ
- API gateway log group: API-Gateway-Execution-Logs_96wd9grlbd/Prod
Query 1.
fields @log, @timestamp, @message| filter @requestId = "576f9ca4-630c-4237-a7a1-a8a44060f2d4" or @message like "620c7d45-353a-4096-9541-1e1a5b8950b9" or @message like "1-6660d328-424386874f29954758acde95" or @message like "6660d328424386874f29954758acde95"| sort @timestamp, @message desc
Query 2 based on trace id.
fields @timestamp, @message| filter @message like "Root=1-6660d328-424386874f29954758acde95"
Let's query.
And see result.
Lambda Handler#
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.# SPDX-License-Identifier: MIT-0import jsonimport boto3import os# model idMODEL_ID = "anthropic.claude-3-haiku-20240307-v1:0"# bedrock runtime clientbedrock_client = boto3.client("bedrock-runtime", region_name=os.environ["REGION"])def call_bedrock(prompt):"""call bedrock claude 3 to describe image"""# body to invoke bedrock claude 3messages = []# current imagemessages.append({"role": "user","content": [{"type": "text", "text": prompt},],})# build bodybody = json.dumps({"anthropic_version": "bedrock-2023-05-31","max_tokens": 2048,"temperature": 0.5,"top_k": 250,"top_p": 0.999,"messages": messages,})# invoke modelresponse = bedrock_client.invoke_model(body=body,contentType="application/json",accept="*/*",modelId=MODEL_ID,)# model responseresponse_body = json.loads(response.get("body").read())# responsereturn response_body["content"][0]["text"]def handler(event, context) -> json:"""simple lambda function"""print(event)# parse image from eventprompt = event["queryStringParameters"]["prompt"]# describe imagebot_response = call_bedrock(prompt)# returnreturn {"statusCode": 200,"headers": {"Access-Control-Allow-Origin": "*","Access-Control-Allow-Headers": "Content-Type","Access-Control-Allow-Methods": "OPTIONS,GET",},"body": json.dumps({"bot": bot_response}),}if __name__ == "__main__":res = handler(event={"queryStringParameters": {"prompt": "how to cook chicken soup?"}},context=None,)print(res)