Skip to content

[AWSLambda] Support the datasource faas.trigger type for S3 events #5178

Description

@ashishsinghnr

Component

OpenTelemetry.Instrumentation.AWSLambda

Is your feature request related to a problem?

GetFaasTrigger classifies HTTP triggers as http and, SQS/SNS triggers as pubsub. Every other event source still reportsfaas.trigger = other, including S3.

A function triggered by an S3 object event is responding to a data source operation, which the conventions describe as the datasource trigger type. The conventions name S3 explicitly in the attribute definitions:

  • faas.document.collection:
    "The name of the source on which the triggering operation was performed. For example, in Cloud Storage or S3 corresponds to the bucket name"
  • faas.document.name:
    "The document name/table subjected to the operation. For example, in Cloud Storage or S3 is the name of the file"

So S3 is not an inferred fit for datasource — it is one of the two examples the specification was written around, and it currently reports other.

What is the expected behavior?

Report faas.trigger = datasource for S3 events, together with the faas.document.* attributes the conventions require.

Only datasource is not satisfied by setting faas.trigger alone. The Datasource section
requires:

Attribute Requirement level
faas.document.collection Required
faas.document.operation Required
faas.document.name Recommended
faas.document.time Recommended

Setting faas.trigger = datasource without the two required attributes would be less conformant than the current other, so the attributes have to be part of the same change.

S3 maps completely. Every attribute has a real property on S3Event.S3EventNotificationRecord :

Attribute Source Type
faas.document.collection S3.Bucket.Name string
faas.document.name S3.Object.Key string
faas.document.operation EventName, mapped below string
faas.document.time EventTime DateTime

Both Required attributes come from real properties, which is what makes S3 implementable today: collection is S3.Bucket.Name directly, and operation is derived from EventName. Note that faas.document.time is typed as a string in the conventions while EventTime is a DateTime, so it would be formatted as ISO 8601 with an invariant culture rather than via a default ToString().

Batching is not a problem for S3. The S3 documentation states that "Amazon S3 event notifications send one event entry for each notification message", and S3 invokes Lambda by asynchronous push rather than through a polled event source mapping. So an S3Event normally carries a single record, and the per-record faas.document.* attributes describe the invocation unambiguously.

Trigger detection mirrors the merged pubsub change and stays small:

private static bool IsDatasourceRequest<TInput>(TInput input) =>
    input is S3Event or S3Event.S3EventNotificationRecord;

private static string GetFaasTrigger<TInput>(TInput input)
{
    if (IsHttpRequest(input))
    {
        return "http";
    }

    if (IsPubSubRequest(input))
    {
        return "pubsub";
    }

    return IsDatasourceRequest(input) ? "datasource" : "other";
}

The record-level type is included for the same reason #5146 included SQSEvent.SQSMessage and SNSEvent.SNSRecord: a handler may take an individual record, and GetFaasTrigger should classify it consistently with the batch type.

Which alternative solutions or features have you considered?

Emitting faas.trigger = datasource on its own, without the faas.document.* attributes. This would be a one-line change, but faas.document.collection and faas.document.operation are Required for the
datasource trigger, so the result would be a span that declares itself a datasource invocation and then omits two required attributes. That is arguably worse than the current other, which claims nothing. Rejected.

Leaving S3 as other. Defensible in the sense that nothing is broken today, but other is specified as "if none of the others apply", and datasource demonstrably does apply — the conventions name S3 in the attribute descriptions. Consumers filtering on faas.trigger = datasource to find data-driven invocations silently miss all S3 Lambda spans.

Avoiding the new package dependency by duck typing on the input's type name (input.GetType().FullName == "Amazon.Lambda.S3Events.S3Event") instead of referencing Amazon.Lambda.S3Events. This keeps the dependency footprint unchanged, but reads the bucket and key by reflection or dynamic, which is fragile, harder to unit test, and works against IsAotCompatible=true.

Deriving the attributes in the user's handler rather than the instrumentation. Possible today with Activity.Current?.SetTag(...), but it pushes convention knowledge onto every consumer and would not be consistent across SDKs. This is the kind of mapping the instrumentation exists to do.

Additional context

1. Is a new package dependency on Amazon.Lambda.S3Events acceptable?

This is the only hard blocker. The project currently references Amazon.Lambda.APIGatewayEvents, Amazon.Lambda.ApplicationLoadBalancerEvents, Amazon.Lambda.Core, Amazon.Lambda.SNSEvents and Amazon.Lambda.SQSEvents. Adding Amazon.Lambda.S3Events means a new dependency for every consumer of this package, including those with no S3 triggers, and the project sets IsAotCompatible=true, so the trimming impact would need checking.

2. How should faas.document.operation handle S3's event types?

faas.document.operation has well-known values insert, edit and delete, and the registry states that if one of them applies "then the respective value MUST be used; otherwise, a custom value MAY be used".

S3 sends composite event names, so the mapping has to key off the family prefix before : rather than the whole value. S3 publishes eleven event-type families, of which only two map to a well-known value:
Amazon S3 API Reference:

S3 event family Well-known value
ObjectCreated:Put, :Post, :Copy, :CompleteMultipartUpload insert
ObjectRemoved:Delete, :DeleteMarkerCreated delete
LifecycleExpiration:Delete, :DeleteMarkerCreated delete? — see below
ObjectRestore:*, LifecycleTransition, IntelligentTiering, ObjectTagging:*, ObjectAnnotation:*, ObjectAcl:Put, Replication:*, s3:TestEvent none applies

Further notes

The AWS Lambda conventions do not cover S3. The AWS Lambda page has specific sections for API Gateway and SQS but none for S3, so only the generic FaaS Datasource section applies. Given that section names S3 directly? may be we would rather need a clarificationraised in semantic-conventions first ?

All four faas.document.* attributes are Development stability, consistent with the other experimental FaaS attributes this instrumentation already emits.

Tip

React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions