haseebhashim/laravel-cloudwatch-logger

AWS CloudWatch logging driver for Laravel

Maintainers

Package info

github.com/haseebhashim/laravel-cloudwatch-logger

pkg:composer/haseebhashim/laravel-cloudwatch-logger

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-05-07 11:07 UTC

This package is auto-updated.

Last update: 2026-05-07 11:08:02 UTC


README

Latest Version on Packagist Total Downloads License

AWS CloudWatch Logs handler for Laravel. It plugs into Laravel's standard logging system through Monolog, creates the configured log group and stream when needed, and sends application logs to CloudWatch.

Features

  • Laravel logging channel support through Monolog
  • Automatic CloudWatch log group and log stream creation
  • Optional log retention policy setup
  • Sequence token discovery and retry handling
  • Supports AWS access keys or the default AWS credential provider chain
  • Dynamic stream placeholders for hostname, environment, and date
  • Compatible with Laravel 10, 11, and 12

Requirements

  • PHP 8.1 or higher
  • Laravel 10, 11, or 12
  • AWS credentials with CloudWatch Logs permissions

Installation

Install the package with Composer:

composer require haseebhashim/laravel-cloudwatch-logger

Laravel auto-discovers the service provider. If package auto-discovery is disabled, register the provider manually:

HaseebHashim\CloudWatchLogs\CloudWatchLogsServiceProvider::class,

Publish the configuration file:

php artisan vendor:publish --provider="HaseebHashim\CloudWatchLogs\CloudWatchLogsServiceProvider" --tag="config"

Environment

Add the values you need to your .env file:

AWS_DEFAULT_REGION=us-east-1

# Optional when you use IAM roles, ECS/EKS task roles, SSO, or another AWS provider.
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=

CLOUDWATCH_LOG_GROUP=laravel-app
CLOUDWATCH_LOG_STREAM="${APP_ENV}-{{hostname}}"
CLOUDWATCH_LOG_RETENTION=30
CLOUDWATCH_LOG_LEVEL=debug

Supported stream placeholders:

  • {{hostname}}: server hostname
  • {{env}}: Laravel application environment
  • {{date}}: current date in YYYY-MM-DD format

Set CLOUDWATCH_LOG_RETENTION=null in config/cloudwatch-logs.php if you want CloudWatch to keep logs indefinitely.

Laravel Logging Channel

Add a CloudWatch channel to config/logging.php:

use HaseebHashim\CloudWatchLogs\Logging\CloudWatchLogger;
use Monolog\Formatter\JsonFormatter;

'channels' => [
    'cloudwatch' => [
        'driver' => 'monolog',
        'handler' => CloudWatchLogger::class,
        'level' => env('CLOUDWATCH_LOG_LEVEL', 'debug'),
        'formatter' => JsonFormatter::class,
    ],

    'stack' => [
        'driver' => 'stack',
        'channels' => ['daily', 'cloudwatch'],
        'ignore_exceptions' => false,
    ],
],

Use Laravel logging normally:

use Illuminate\Support\Facades\Log;

Log::info('User logged in', [
    'user_id' => auth()->id(),
    'ip' => request()->ip(),
]);

Log::channel('cloudwatch')->error('Payment failed', [
    'payment_id' => $payment->id,
]);

AWS Permissions

The AWS user or role needs these CloudWatch Logs permissions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:DescribeLogStreams",
        "logs:PutLogEvents",
        "logs:PutRetentionPolicy"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    }
  ]
}

If you create the log group and retention policy yourself, you can remove logs:CreateLogGroup and logs:PutRetentionPolicy from the application's runtime role.

Configuration

The published config file is config/cloudwatch-logs.php.

return [
    'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),

    'credentials' => [
        'key' => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
    ],

    'log_group' => env('CLOUDWATCH_LOG_GROUP', 'laravel-app'),
    'log_stream' => env('CLOUDWATCH_LOG_STREAM', php_uname('n')),
    'retention' => env('CLOUDWATCH_LOG_RETENTION', 30),
    'level' => env('CLOUDWATCH_LOG_LEVEL', 'debug'),
];

When AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are empty, the AWS SDK uses its normal credential provider chain. This is usually best for production on AWS infrastructure.

Test A Log

You can verify the channel from Tinker:

php artisan tinker
Log::channel('cloudwatch')->info('CloudWatch test log', ['time' => now()->toISOString()]);

Then check the configured log group and stream in the AWS CloudWatch console.

Troubleshooting

Logs do not appear in CloudWatch

  • Confirm AWS_DEFAULT_REGION matches the region you are viewing in AWS.
  • Confirm the log group and stream names match your .env values.
  • Confirm the IAM user or role has logs:PutLogEvents and logs:DescribeLogStreams.
  • Check storage/logs/laravel.log for local application errors.

Missing credentials

  • Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or run the app with an IAM role / task role / configured AWS profile.

ResourceAlreadyExistsException

  • This is expected when the log group or stream already exists. The handler catches that AWS response and continues.

InvalidSequenceTokenException

  • The handler refreshes the sequence token from the AWS error message and retries the write.

Development

Install dependencies:

composer install

Run the test suite:

composer test

Run a syntax check:

composer lint

Validate the Composer package metadata:

composer validate --strict

License

The MIT License. See LICENSE.txt.