Adding XRAY Tracing to non-rest functions e.g., SQS, Cognito Triggers etc - serverless-framework

Using the Serverless framework, I have functions that aren’t attached to an API Gateway Endpoint, such as:
Cognito Triggers
S3 Event
DynamoDB Stream
SQS Events
I am also using XRAY tracing, which I have set as tracing: true in my serverless.yml file. It seems that these functions are not being traced, the debug message I receive is:
Ignoring flush on subsegment 20dcd559aa2ab487. Associated segment is marked as not sampled.
Is there any way to have these functions added, either via serverless or cloudformation?
Thanks in advance.

To enable X-Ray tracing for all your Service’s Lambda functions you just need to set the corresponding tracing configuration on the provider level:
provider:
tracing:
lambda: true
If you want to setup tracing on a per-function level you can use the tracing config in your function definition:
functions:
myFunction:
handler: index.handler
tracing: true
Setting tracing to true translates to the Active tracing configuration. You can overwrite this behavior by providing the desired configuration as a string:
functions:
myFunction:
handler: index.handler
tracing: PassThrough
Also note that you can mix the provider- and function-level configurations. All functions will inherit the provider-level configuration which can then be overwritten on an individual function basis:
service:
name: my-tracing-service
provider:
name: aws
stage: dev
runtime: nodejs8.10
tracing:
lambda: true
functions:
myFunc1: # this function will inherit the provider-level tracing configuration
handler: index.func1
myFunc2:
handler: handler.func2
tracing: PassThrough # here we're overwriting the provider-level configuration
It's recommended to setup X-Ray tracing for Lambda with the aforementioned tracing configuration since doing so will ensure that the X-Ray setup is managed by the Serverless Framework core via CloudFormation.
You can get more granular and specify which resources you want traced as well:
Open your serverless.yml and add a tracing config inside the provider section:
provider:
...
tracing:
apiGateway: true
lambda: true
IMPORTANT: Due to CloudFormation limitations it's not possible to enable AWS X-Ray Tracing on existing deployments which don’t use tracing right now.
Please remove the old Serverless Deployments and re-deploy your lambdas with tracing enabled if you want to use AWS X-Ray Tracing for Lambda.
Lastly, don't forget to have the right IAM permission policies configured:
provider:
...
iamRoleStatements:
- Effect: Allow
Action:
...
- xray:PutTraceSegments
- xray:PutTelemetryRecords
Resource: "*"
To enable X-Ray tracing for other AWS services invoked by AWS Lambda, you MUST Install the AWS X-Ray SDK. In your project directory, run:
$ npm install -s aws-xray-sdk
Update your Lambda code and wrap AWS SDK with the X-Ray SDK. Change:
const AWS = require('aws-sdk');
To:
const AWSXRay = require('aws-xray-sdk-core');
const AWS = AWSXRay.captureAWS(require('aws-sdk'));
As of Release Serverless v140

At the moment Lambda doesn't support continuing traces from triggers other than REST APIs or direct invocation
The upstream service can be an instrumented web application or another Lambda function. Your service can invoke the function directly with an instrumented AWS SDK client, or by calling an API Gateway API with an instrumented HTTP client.
https://docs.aws.amazon.com/xray/latest/devguide/xray-services-lambda.html
In every other case it will create its own, new Trace ID and use that instead.
You can work around this yourself by creating a new AWS-Xray segment inside the Lambda Function and using the incoming TraceID from the SQS message. This will result in two Segments for your lambda invocation. One which Lambda itself creates, and one which you create to extend the existing trace. Whether that's acceptable or not for your use case is something you'll have to decide for yourself!
If you're working with Python you can do it with aws-xray-lambda-segment-shim.
If you're working with NodeJS you can follow this guide on dev.to.
If you're working with .NET there are some examples on this GitHub issue.

Related

stage is not added to the endpoint when deploy with sls deploy --stage dev

I am using serverless framework. I have set the stage as the dev and deploying using sls deploy --stage dev command. The dev stage is not added to the end point. The endpoints are not like the one given below:
https://****.execute-api.us-east-1.amazonaws.com/users
One of my lambda functions needs an endpoint to submit a post request to a third-party API to post back the result. I need to be sure that the endpoint is rightly sent from the production/dev stage.
postback_url = `https://${process.env.RestApiId}.execute-api.${
process.env.REGION
}.amazonaws.com/${process.env.stage}/dfs-pingback?id=$id&tag=$tag`;
As you can see the above postback url is wrong if I do not get the stage (process.env.stage) added to the endpoint.
serverless.yml
service: lytoolsApi
frameworkVersion: '2 || 3'
configValidationMode: error
provider:
name: aws
runtime: nodejs12.x
region: us-east-1
stage: dev
Serverless Framework does things a bit differently and instead of using stages of APIGW, it creates a totally new APIGW for each stage, that's why you don't see the prefix in your path with the stage name, but if you observe the url, you'll see that the base url will be different across stages. That's how you can differentiate between them.

Cant get hierarchic properties by S3 Backend spring config server

I created spring config server with s3 backend as it described here:
https://cloud.spring.io/spring-cloud-config/reference/html/#_aws_s3_backend
I created 4 files in my-config-server s3 bucket:
app-default.properties
app-dev.properties
client-app-default.properties
client-app-dev.properties
When I ran client-app application with dev profile, I got only client-app-dev.properties properties.
I am interested if it is possible to get also client-app-default.properties, app-dev.properties and app-default.properties properties, if its were not defined in client-app-dev.properties
In another words, Is it possible to support following hierarchic:
application.properties # Applicable for all environments.
application-dev.properties # Environment level commons across all services.
client-app-dev.properties # Overrides specific to the service for one environment.
client-app2-dev.properties
for example:
client-app-dev.properties
my.property1="my-propertyDev1"
client-app-default.properties
my.property1="my-propertyDefault1"
my.property2="my-property2Default"
app-default.properties
my.property3="my-propertyAppDefault3"
when I am running client-app application with dev profile I what to get:
#Value("${my.property1}")
private String property1; //"my-propertyDev1"
#Value("${my.property2}")
private String property2; //"my-property2Default"
#Value("${my.property3}")
private String property3; //"my-propertyAppDefault3"
It works so with regular spring config server but I didn't succeed with s3 backed. It goes directly to specific app and specific profile

Spinnaker - SQL backend for front50

I am trying to setup SQL backend for front50 using the document below.
https://www.spinnaker.io/setup/productionize/persistence/front50-sql/
I have fron50-local.yaml for the mysql config.
But, not sure how to disable persistent storage in halyard config. Here, I can not completely remove persistentStorage and persistentStoreType should be one of a3,azs,gcs,redis,s3,oracle.
There is no option to disable persistent storage here.
persistentStorage:
persistentStoreType: s3
azs: {}
gcs:
rootFolder: front50
redis: {}
s3:
bucket: spinnaker
rootFolder: front50
maxKeys: 1000
oracle: {}
So within your front50-local.yaml you will want to disable the service you used to utilize e.g.
spinnaker:
gcs:
enabled: false
s3:
enabled: false
You may need/want to remove the section from your halconfig and run your apply with
hal deploy apply --no-validate
There are a number of users dealing with these same issues and some more help might be found on the Slack: https://join.spinnaker.io/
I've noticed the same issue just recently. Maybe this is because, for example Kayenta (which is an optional component to enable) is still missing the non-object storage persistent support, or...
I've created a GitHub issue on this here: https://github.com/spinnaker/spinnaker/issues/5447

How to programmatically set up Airflow 1.10 logging with localstack s3 endpoint?

In attempt to setup airflow logging to localstack s3 buckets, for local and kubernetes dev environments, I am following the airflow documentation for logging to s3. To give a little context, localstack is a local AWS cloud stack with AWS services including s3 running locally.
I added the following environment variables to my airflow containers similar to this other stack overflow post in attempt to log to my local s3 buckets. This is what I added to docker-compose.yaml for all airflow containers:
- AIRFLOW__CORE__REMOTE_LOGGING=True
- AIRFLOW__CORE__REMOTE_BASE_LOG_FOLDER=s3://local-airflow-logs
- AIRFLOW__CORE__REMOTE_LOG_CONN_ID=MyS3Conn
- AIRFLOW__CORE__ENCRYPT_S3_LOGS=False
I've also added my localstack s3 creds to airflow.cfg
[MyS3Conn]
aws_access_key_id = foo
aws_secret_access_key = bar
aws_default_region = us-east-1
host = http://localstack:4572 # s3 port. not sure if this is right place for it
Additionally, I've installed apache-airflow[hooks], and apache-airflow[s3], though it's not clear which one is really needed based on the documentation.
I've followed the steps in a previous stack overflow post in attempt verify if the S3Hook can write to my localstack s3 instance:
from airflow.hooks import S3Hook
s3 = S3Hook(aws_conn_id='MyS3Conn')
s3.load_string('test','test',bucket_name='local-airflow-logs')
But I get botocore.exceptions.NoCredentialsError: Unable to locate credentials.
After adding credentials to airflow console under /admin/connection/edit as depicted:
this is the new exception, botocore.exceptions.ClientError: An error occurred (InvalidAccessKeyId) when calling the PutObject operation: The AWS Access Key Id you provided does not exist in our records. is returned. Other people have encountered this same issue and it may have been related to networking.
Regardless, a programatic setup is needed, not a manual one.
I was able to access the bucket using a standalone Python script (entering AWS credentials explicitly with boto), but it needs to work as part of airflow.
Is there a proper way to set up host / port / credentials for S3Hook by adding MyS3Conn to airflow.cfg?
Based on the airflow s3 hooks source code, it seems a custom s3 URL may not yet be supported by airflow. However, based on the airflow aws_hook source code (parent) it seems it should be possible to set the endpoint_url including port, and it should be read from airflow.cfg.
I am able to inspect and write to my s3 bucket in localstack using boto alone. Also, curl http://localstack:4572/local-mochi-airflow-logs returns the contents of the bucket from the airflow container. And aws --endpoint-url=http://localhost:4572 s3 ls returns Could not connect to the endpoint URL: "http://localhost:4572/".
What other steps might be needed to log to localstack s3 buckets from airflow running in docker, with automated setup and is this even supported yet?
I think you're supposed to use localhost not localstack for the endpoint, e.g. host = http://localhost:4572.
In Airflow 1.10 you can override the endpoint on a per-connection basis but unfortunately it only supports one endpoint at a time so you'd be changing it for all AWS hooks using the connection. To override it, edit the relevant connection and in the "Extra" field put:
{"host": "http://localhost:4572"}
I believe this will fix it?
I managed to make this work by referring to this guide. Basically you need to create a connection using the Connection class and pass the credentials that you need, in my case I needed AWS_SESSION_TOKEN, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, REGION_NAME to make this work. Use this function as a python_callable in a PythonOperator which should be the first part of the DAG.
import os
import json
from airflow.models.connection import Connection
from airflow.exceptions import AirflowFailException
def _create_connection(**context):
"""
Sets the connection information about the environment using the Connection
class instead of doing it manually in the Airflow UI
"""
AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
AWS_SESSION_TOKEN = os.getenv("AWS_SESSION_TOKEN")
REGION_NAME = os.getenv("REGION_NAME")
credentials = [
AWS_SESSION_TOKEN,
AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY,
REGION_NAME,
]
if not credentials or any(not credential for credential in credentials):
raise AirflowFailException("Environment variables were not passed")
extras = json.dumps(
dict(
aws_session_token=AWS_SESSION_TOKEN,
aws_access_key_id=AWS_ACCESS_KEY_ID,
aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
region_name=REGION_NAME,
),
)
try:
Connection(
conn_id="s3_con",
conn_type="S3",
extra=extras,
)
except Exception as e:
raise AirflowFailException(
f"Error creating connection to Airflow :{e!r}",
)

How to determine the Cloudwatch log stream for a Fargate service?

I've got a Fargate service running, and can view its Cloudwatch log streams using the AWS console (navigate to the service, and click on its Logs tab).
I'm looking at the AWS documentation for GetLogEvents and see that you can access the logs using the log group name and log stream name. While I know the log group name for the service, the log stream name is generated dynamically.
How do I obtain the current log stream name for the running Fargate service?
I'm checking the AmazonECSClient documentation, any pointers would be helpful.
EDIT:
I found that the log group is actually specified for the container, not the service. Retrieving the task definition for the service, I can iterate over the container definitions which have the LogConfiguration section that indicates the Options, however that only provides the log group and a stream prefix, no log stream name:
- service
- task definition
- container definitions
- LogConfiguration:
LogDriver: awslogs
Options: awslogs-group=/ecs/myservice
awslogs-region=us-east-1
awslogs-stream-prefix=ecs
EDIT 2:
I see from the AWS Console, that the link in the Logs tab does contain the log stream name. See the stream value in this sample URL:
https://us-east-1.console.aws.amazon.com/cloudwatch/home
?region=us-east-1
#logEventViewer:group=/ecs/myservice;stream=ecs/myservice/ad7246dd-bb0e-4eff-b059-767d30d40e69
How does the AWS Console obtain that value?
I finally found the format of the log stream name in the AWS documentation here:
awslogs-stream-prefix
Required: No, unless using the Fargate launch type in which case it is required.
The awslogs-stream-prefix option allows you to associate a log stream
with the specified prefix, the container name, and the ID of the Amazon
ECS task to which the container belongs. If you specify a prefix with
this option, then the log stream takes the following format:
prefix-name/container-name/ecs-task-id
Note that the ecs-task-id is the GUID portion of the task's ARN:
For this sample Task ARN:
arn:aws:ecs:us-east-1:123456789012:task/12373b3b-84c1-4398-850b-4caef9a983fc
the ecs-task-id to use for the log stream name is:
12373b3b-84c1-4398-850b-4caef9a983fc