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

Laravel Cloudwatch Logger Laravel Package

tarfin-labs/laravel-cloudwatch-logger

Send Laravel application logs directly to AWS CloudWatch Logs with this ready-to-use logging driver. Configure a log group and stream, then let Laravel’s logging system ship messages to AWS for centralized monitoring and retention.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install: composer require tarfin-labs/laravel-cloudwatch-logger. On v2.7.0 the dependency set targets Laravel 12 / PHP 8.4, so if you're still on Laravel 10/11 or PHP 8.2–8.3, first run composer why-not tarfin-labs/laravel-cloudwatch-logger ^2.7 — if it's blocked by aws/aws-sdk-php or framework constraints, stay on ^2.6 until you upgrade.
  • Publish the config (php artisan vendor:publish --tag=cloudwatch-logger or --provider="TarfinLabs\CloudwatchLogger\CloudwatchLoggerServiceProvider") and read the published file once before wiring anything — group name, stream name, region, retention and batch/flush settings all live there and are the source of truth for your version.
  • Credentials: prefer the SDK default chain (IAM instance role / ECS task role) and leave explicit keys unset in production. Only put AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY in .env for local experiments — never in a repo that also runs locally.
  • Register the channel in config/logging.php as a custom driver pointing at the package's logger factory, e.g. 'cloudwatch' => ['driver' => 'custom', 'via' => \TarfinLabs\CloudwatchLogger\CloudwatchLoggerFactory::class].
  • First use case: don't flip LOG_CHANNEL globally. Add a stack channel ('production' => ['driver' => 'stack', 'channels' => ['single', 'cloudwatch']]) so you get local files and CloudWatch, then verify with LOG_CHANNEL=cloudwatch php artisan tinker → Log::info('hello from tinker') and check the stream in the console (allow a few seconds for ingestion).

Implementation Patterns

  • Environment-scoped stacks. Keep single/daily as the default locally and only stack CloudWatch in staging/production. The cleanest version is a dedicated production stack selected via LOG_STACK in .env, so nothing in code branches on App::environment().
  • One group per concern, not per app. Use separate log groups (or at least separate streams) for app, audit, jobs, payments. CloudWatch retention, IAM scoping and metric filters are all per-group, so mixing them forces you to over-grant and over-retain.
  • Make stream names unique and bounded. A stream name like {app}-{env}-{date} or {app}-{env}-{hostname} avoids the classic "all FPM workers hammer one stream" problem and keeps streams from growing forever. Set the group retention in config (e.g. 14/30 days) rather than relying on infinite retention defaults.
  • Long-running processes need an explicit flush. Under queue workers, octane, and scheduler:work, records sit in the handler's buffer until the batch threshold or shutdown. If you deploy long-lived workers, confirm entries actually arrive; call the framework's shutdown/close path (or Log::close() where appropriate) before a worker sleeps or restarts.
  • Structured context beats string concatenation. Log::error('Payment failed', ['order_id' => $id, 'gateway' => $gw]) keeps messages greppable and makes CloudWatch Logs Insights queries (fields @message | filter @message like /order_id/) actually usable.
  • Provision AWS out-of-band. Create the log group and retention policy in Terraform/CDK and grant the app only logs:CreateLogStream + logs:PutLogEvents. Letting the app create groups makes deploys order-dependent and quietly expands IAM permissions.
  • Close the loop with metric filters → alarms. The value of shipping to CloudWatch is alarms on ERROR counts per group; wire that up in the same PR as the logging change, otherwise you've only moved your log files.
  • Tests: pin LOG_CHANNEL=null (or single) in phpunit.xml and never let the suite talk to AWS. If you must assert on emitted logs, bind a fake/memory handler instead of the CloudWatch channel.

Gotchas and Tips

  • v2.7.0 is a dependency-only release. There is no API, config-key, or behaviour change — the only reason to care is framework/runtime compatibility. It's a low-risk bump, but it will move aws/aws-sdk-php in your lockfile, so run the suite and deploy to staging before production, and commit composer.lock. If you pin the SDK with a tight constraint or a fork, relax it first or composer update will fail to resolve.
  • IAM is the #1 silent failure. Missing logs:DescribeLogStreams or logs:CreateLogStream typically surfaces as an exception on flush (often at end of request, so it looks like a random 500) rather than at boot. Test with a fresh role, not your admin credentials.
  • Eventual consistency on first deploy. A freshly created group/stream can return ResourceNotFoundException for a second or two. Transient errors on the very first request after provisioning are normal; persistent ones are permissions or wrong region.
  • Buffered writes lose data on hard failures. Fatal errors, OOM kills, exit, and container SIGKILL bypass the flush. If an entry must survive, keep the local single channel in the stack and/or ship stderr to the platform's log driver as a backstop.
  • Duplicate entries are possible. Retries after a partial failure can re-send a batch; there's no dedupe. Don't build exactly-once counting on top of CloudWatch ingestion.
  • Throttling and sequence tokens. Many concurrent writers on a single stream invite throttling; per-host/per-day stream names are the cheap fix. If you see InvalidSequenceTokenException-style errors, that's the signal.
  • Cost is per GB ingested, and debug is expensive. Set the channel's minimum level to warning (or notice) in production and keep debug for local only. Also remember CloudWatch Logs has per-request overhead — very chatty logging gets slow because the flush is a synchronous SDK call inside the request; set sane connect/request timeouts so CloudWatch latency never becomes your latency.
  • Wrong log group usually means wrong region. The most common "logs aren't arriving" case is credentials/region resolving to something other than what you're looking at in the console. Check AWS_DEFAULT_REGION and any cached config (php artisan config:clear) after env changes.
  • Extension point: if you need to reshape the payload (extra keys, custom group per tenant), decorate around the logger rather than editing the package — build a small custom channel/factory that wraps it, so composer update stays painless across future minor bumps.
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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route