Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Contrib Aws Laravel Package

open-telemetry/contrib-aws

AWS integrations for OpenTelemetry PHP: provides an AWS X-Ray propagator and trace ID generator so PHP services can join X-Ray traces and correlate telemetry across AWS services. Install via Composer to add AWS-aware context propagation to your instrumentation.

View on GitHub
Deep Wiki
Context7

Getting Started

open-telemetry/contrib-aws is a thin auto-instrumentation layer for the AWS SDK for PHP. It wraps AWS client calls so each API operation (S3.PutObject, SQS.SendMessage, DynamoDB.GetItem, etc.) produces a span with AWS semantic attributes such as service name, operation, region, request ID, HTTP status, and error information. It does not ship a Laravel service provider, config file, or facade — you own the wiring.

Minimal install

composer require open-telemetry/contrib-aws open-telemetry/sdk open-telemetry/exporter-otlp

You also need the OpenTelemetry PHP API/SDK bootstrapped. Most Laravel apps do this in a dedicated service provider or a small bootstrap file. Configure the tracer provider, resource (service.name, deployment.environment), sampler, and OTLP exporter once, then reuse it.

What to read first

  1. The package README — it is the only contract for the instrumentation API.
  2. src/ — confirm the exact instrumentation class and whether registration is instrument($client), a static register(...), or an SDK middleware added to the handler list.
  3. tests/ — the fastest way to see a working client registration with the exact constructor signatures for the tagged version.
  4. The AWS SDK’s Middleware/HandlerList docs — the instrumentation ultimately hooks there, and knowing that makes edge cases understandable.

First use case

Trace an S3 upload from a queued job. Build the tracer provider, instantiate the instrumentation with it, apply the instrumentation to the S3Client, and dispatch the job. You should see a parent job/consumer span, an S3.PutObject span beneath it, and (if Guzzle is also instrumented) an HTTP client span beneath that. That three-level shape is the quickest way to confirm both the package and your context propagation are working.

A typical registration shape — verify the exact signature against your installed version:

use OpenTelemetry\Contrib\Aws\AwsSdkInstrumentation;

$instrumentation = new AwsSdkInstrumentation($tracerProvider);
$instrumentation->instrument($s3Client);

$s3Client->putObject([...]);

If the class or method name differs in your tag, adapt the call rather than assuming this snippet is stable. This package has effectively no downstream usage, so the source is the documentation.

Implementation Patterns

Centralize and decorate client creation. Instrumentation applied ad hoc in controllers gets missed. Bind instrumented clients in the container and inject them:

$this->app->singleton(S3Client::class, function ($app) {
    $client = new S3Client(config('filesystems.disks.s3'));
    $app->make(AwsSdkInstrumentation::class)->instrument($client);
    return $client;
});

Then use that binding everywhere, including repositories and jobs. Keep raw new S3Client(...) out of application code.

Laravel’s S3 filesystem disk needs an explicit hook. Storage::disk('s3') constructs its own Aws\S3\S3Client inside FilesystemManager, so container bindings alone won’t instrument it. Extend the driver or register a custom disk:

Storage::extend('s3', function ($app, $config) {
    $client = $app->make(InstrumentedS3ClientFactory::class)->make($config);
    $adapter = new \League\Flysystem\AwsS3V3\AwsS3V3Adapter(
        $client, $config['bucket'], $config['root'] ?? '', null, null, $config['options'] ?? []
    );
    return new \Illuminate\Filesystem\FilesystemAdapter(
        new \League\Flysystem\Filesystem($adapter), $adapter
    );
});

This is the difference between “we trace uploads” and “we trace uploads from the storage layer but not from Storage::put.”

SQS queues: inject the client. Laravel’s SQS connector accepts a client key in the queue config in current versions. Build an instrumented SqsClient and pass it:

'sqs' => [
    'driver' => 'sqs',
    'key' => env('AWS_ACCESS_KEY_ID'),
    // ...
    'client' => app(InstrumentedSqsClient::class),
],

If your Laravel version constructs the client unconditionally, subclass SqsConnector and override the client factory method.

Propagate context across SQS. Instrumenting SendMessage gives you a producer span, but the consumer is a separate trace unless you carry the W3C traceparent. Two workable options:

  • Put traceparent in the SQS MessageAttributes by subclassing SqsQueue or decorating the producer call, then extract it in a JobProcessing listener and start the consumer span as a child.
  • Use Queue::createPayloadUsing() to add trace context to the job payload, then extract it in a listener. Less standard than message attributes, but much easier to wire in a stock Laravel app.

Pair either approach with a JobProcessing/JobProcessed/JobFailed listener that starts and ends a consumer span, so the trace is continuous across the queue boundary. Without this you get two disconnected traces.

Async clients. If you use invokeAsync or promise-based calls, confirm the package ends the span on resolution and records rejection. If it doesn’t, wrap the promise yourself and end the span in then/otherwise, with a finally guard against never-resolving promises.

Sampling. Use a parent-based sampler in the web/worker bootstrap. A root-only sampler will drop AWS spans in requests that were sampled upstream, or create orphaned traces. Set resource attributes once at bootstrap:

$resource = ResourceInfo::create(Attributes::create([
    'service.name' => config('app.name'),
    'deployment.environment' => app()->environment(),
]));

Testing. Use an in-memory exporter with a simple span processor in a test-only provider, instrument a client, invoke it, and assert span names and attributes. Disable instrumentation globally in phpunit.xml and enable it only in the tests that assert telemetry, otherwise every test pays the exporter cost.

Gotchas and Tips

  • Low adoption is the headline risk. Zero stars, zero dependents, and a very recent release mean the API surface is effectively unproven. Pin an exact version, read the source for your tag, and wrap instrumentation in your own small adapter class so a package change touches one file.
  • Double spans from Guzzle. The AWS SDK uses Guzzle. If you also instrument Guzzle/HTTP clients, you will get AWS operation → HTTP request span pairs. That is usually correct, but it doubles span volume and can make latency dashboards confusing. Either accept it or filter HTTP spans whose host matches AWS endpoints.
  • Credential and metadata noise. IMDS, STS AssumeRole, and credential-refresh calls can generate spans that have nothing to do with your business transaction, especially on cold starts. Filter by operation name or endpoint in the exporter/processor.
  • S3 multipart uploads are chatty. Large uploads produce CreateMultipartUpload, many UploadPart, and CompleteMultipartUpload spans. Budget for it or sample those operations.
  • SQS long polling inflates latency. ReceiveMessage with a 20-second wait time produces 20-second spans. Do not put queue-receive spans on the same latency panels as request spans; separate service or operation filters.
  • AWS errors are not always exceptions. The SDK throws on API-level failures, but batch operations return per-item failures in the result payload. The span may be OK while the payload says three messages failed. Inspect Failed/Errors and record relevant attributes or events yourself if that matters.
  • Long-lived queue workers. Tracer providers, exporters, and instrumentation objects persist across jobs. Flush the exporter on JobProcessed if you buffer, watch memory, and queue:restart after deploys so workers pick up new instrumentation config.
  • Instrument lazily, not at container boot. Instrumenting every configured AWS client on every request adds overhead even for requests that never touch AWS. Resolve instrumented clients only when used.
  • Version compatibility. Confirm the package’s AWS SDK constraint (v3 assumed) and whether it supports async-aws clients at all. If you use AsyncAws rather than aws/aws-sdk-php, verify support before designing around it.
  • Configuration lives in your app, not the package. Exporter endpoint, headers, sampler, and resource are all your responsibility. Put them in config/telemetry.php, but remember config:cache and read env only inside the config file.
  • Extension point is the SDK middleware stack. When the package doesn’t cover a case (custom endpoints, retries, signing), the escape hatch is adding your own middleware to the client’s handler list in the same place the instrumentation does. That is also the cleanest way to add attributes the package omits.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource