Skip to content

Commit b0a60bb

Browse files
authored
v3.0.0 — PHP 8.1 + Monolog 3 modernization (#132)
* Bump PHP min to 8.1 and Monolog to 3.0 * Modernize CloudWatch handler for PHP 8.1 and Monolog 3 - write() now takes Monolog\LogRecord (was array) - Constructor promotion + readonly properties; full type coverage - $level accepts int|string|Monolog\Level (default Level::Debug) - New $createStream argument (10th, default true) — set false to skip DescribeLogStreams + CreateLogStream when the stream is provisioned out of band; lets users drop those IAM permissions - PHPUnit config migrated to 10.x schema * Switch lint to PSR-12 and add phpstan to CI matrix * Update README, CHANGELOG, and CONTRIBUTING for 3.0 * Loosen aws/aws-sdk-php constraint to ^3.0 * Set 3.0.0 release date in CHANGELOG
1 parent c31faa2 commit b0a60bb

11 files changed

Lines changed: 471 additions & 505 deletions

File tree

.github/workflows/php.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
strategy:
1717
fail-fast: false
1818
matrix:
19-
php: ["8.2", "8.3", "8.4", "8.5"]
19+
php: ["8.1", "8.2", "8.3", "8.4", "8.5"]
2020
steps:
2121
- uses: actions/checkout@v4
2222

@@ -29,6 +29,9 @@ jobs:
2929
- name: Lint
3030
run: make PHP=${{ matrix.php }} lint
3131

32+
- name: Static analysis
33+
run: make PHP=${{ matrix.php }} analyse
34+
3235
- name: Tests
3336
run: make PHP=${{ matrix.php }} test
3437

CHANGELOG.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [3.0.0] - 2026-05-03
11+
12+
### Added
13+
14+
- `$createStream` constructor argument (10th, default `true`). Set to `false` to skip `DescribeLogStreams` + `CreateLogStream` when the log stream is provisioned out of band (e.g. via Terraform). Lets users drop the matching IAM permissions.
15+
- Full type coverage on the constructor and properties (constructor promotion, `readonly` for immutable state).
16+
- `phpstan` (level 8) runs in CI alongside lint and tests.
17+
18+
### Changed
19+
20+
- Coding standard upgraded from PSR-2 to PSR-12.
21+
- PHPUnit upgraded to `^10.5 || ^11.0`.
22+
23+
### Removed
24+
25+
- Support for PHP 7.x and 8.0. Minimum PHP is now `^8.1`.
26+
- Support for Monolog 2. Minimum Monolog is now `^3.0`.
27+
28+
### Migration
29+
30+
- Replace any `Monolog\Logger::DEBUG` (or other level constant) usage with `Monolog\Level::Debug`. The `$level` constructor argument continues to accept `int|string|Level` so string values like `'debug'` keep working.
31+
- Symfony service definitions referencing `!php/const Monolog\Logger::WARNING` must change to `!php/const Monolog\Level::Warning`.
32+
- Subclasses overriding `protected function write(array $record): void` must update the signature to `protected function write(\Monolog\LogRecord $record): void` and access fields via `->property` instead of `['key']`.
33+
- The constructor parameter order, names, and defaults of the existing 9 arguments are unchanged. Existing Symfony positional `arguments:` lists and Laravel `with`/`handler_with` named-key configs continue to work after the platform upgrades above.
34+
1035
## [2.1.0] - 2026-04-26
1136

1237
### Added
@@ -36,5 +61,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3661
- **No breaking public API changes.** Adds public `flush()` and overrides `reset()` to flush. Existing constructor and method signatures are unchanged; existing `^2.0` pins continue to work without modification.
3762
- Minimum PHP / Monolog versions unchanged (`^7.2 || ^8` / `monolog/monolog: ^2.0`). CI tests PHP 8.2 – 8.5; no code paths require newer PHP.
3863

39-
[Unreleased]: https://github.com/maxbanton/cwh/compare/v2.1.0...HEAD
64+
[Unreleased]: https://github.com/maxbanton/cwh/compare/v3.0.0...HEAD
65+
[3.0.0]: https://github.com/maxbanton/cwh/compare/v2.1.0...v3.0.0
4066
[2.1.0]: https://github.com/maxbanton/cwh/compare/v2.0.4...v2.1.0

CONTRIBUTING.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,18 @@
1616

1717
Changes that are cosmetic in nature and do not add anything substantial to the stability, functionality, or testability will generally not be accepted.
1818

19+
#### **Local development**
20+
21+
Use the Makefile targets — they run inside Docker against the supported PHP matrix and exactly match what CI runs. Direct `phpunit`/`phpcs`/`phpstan` invocations on your host may pick up a different PHP version or dependency set:
22+
23+
```bash
24+
make build-svc PHP=8.4 # build the dev container
25+
make install PHP=8.4 # composer install inside it
26+
make lint # PSR-12 lint via phpcs
27+
make lint-fix # auto-fix PSR-12 violations via phpcbf
28+
make analyse # phpstan level 8
29+
make test # PHPUnit
30+
make matrix # run install + lint + test across PHP 8.1–8.5 in parallel
31+
```
32+
1933
Thanks!

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ test-coverage:
2525
$(DC) vendor/bin/phpunit --coverage-text --coverage-clover build/logs/clover.xml
2626

2727
lint:
28-
$(DC) vendor/bin/phpcs --standard=psr2 --ignore=Tests src/
28+
$(DC) vendor/bin/phpcs --standard=PSR12 --ignore=Tests src/
2929

3030
lint-fix:
31-
$(DC) vendor/bin/phpcbf --standard=psr2 --ignore=Tests src/
31+
$(DC) vendor/bin/phpcbf --standard=PSR12 --ignore=Tests src/
3232

3333
analyse:
3434
$(DC) vendor/bin/phpstan analyse --level=8 src/
@@ -40,7 +40,7 @@ shell:
4040
$(DC) bash
4141

4242
matrix:
43-
@printf '8.2\n8.3\n8.4\n8.5\n' | xargs -n1 -P4 -I{} $(MAKE) PHP={} install ci
43+
@printf '8.1\n8.2\n8.3\n8.4\n8.5\n' | xargs -n1 -P5 -I{} $(MAKE) PHP={} install ci
4444

4545
clean:
4646
$(COMPOSE) down -v

README.md

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ Please press **★ Star** button if you find this library useful.
1919
This library uses AWS API through AWS PHP SDK, which has limits on concurrent requests. It means that on high concurrent or high load applications it may not work on it's best way. Please consider using another solution such as logging to the stdout and redirecting logs with fluentd.
2020

2121
## Requirements
22-
* PHP ^7.3
22+
* PHP ^8.1
23+
* Monolog ^3.0
2324
* AWS account with proper permissions (see list of permissions below)
2425

2526
## Features
@@ -32,7 +33,7 @@ This library uses AWS API through AWS PHP SDK, which has limits on concurrent re
3233
Install the latest version with [Composer](https://getcomposer.org/) by running
3334

3435
```bash
35-
$ composer require maxbanton/cwh:^2.0
36+
$ composer require maxbanton/cwh:^3.0
3637
```
3738

3839
## Basic Usage
@@ -41,8 +42,9 @@ $ composer require maxbanton/cwh:^2.0
4142

4243
use Aws\CloudWatchLogs\CloudWatchLogsClient;
4344
use Maxbanton\Cwh\Handler\CloudWatch;
44-
use Monolog\Logger;
4545
use Monolog\Formatter\JsonFormatter;
46+
use Monolog\Level;
47+
use Monolog\Logger;
4648

4749
$sdkParams = [
4850
'region' => 'eu-west-1',
@@ -67,7 +69,12 @@ $streamName = 'ec2-instance-1';
6769
$retentionDays = 30;
6870

6971
// Instantiate handler (tags are optional)
70-
$handler = new CloudWatch($client, $groupName, $streamName, $retentionDays, 10000, ['my-awesome-tag' => 'tag-value']);
72+
$handler = new CloudWatch($client, $groupName, $streamName, $retentionDays, 10000, ['my-awesome-tag' => 'tag-value'], Level::Debug);
73+
74+
// Set $createStream to false (10th argument) when the log stream is provisioned out of band
75+
// (e.g. via Terraform `aws_cloudwatch_log_stream`). This skips DescribeLogStreams + CreateLogStream
76+
// and lets you drop the matching IAM permissions.
77+
// $handler = new CloudWatch($client, $groupName, $streamName, $retentionDays, 10000, [], Level::Debug, true, true, false);
7178

7279
// Optionally set the JsonFormatter to be able to access your log messages in a structured way
7380
$handler->setFormatter(new JsonFormatter());
@@ -106,12 +113,24 @@ $client = new CloudWatchLogsClient([
106113
```
107114

108115
## Frameworks integration
109-
- [Silex](http://silex.sensiolabs.org/doc/master/providers/monolog.html#customization)
110-
- [Symfony](http://symfony.com/doc/current/logging.html) ([Example](https://github.com/maxbanton/cwh/issues/10#issuecomment-296173601))
111-
- [Lumen](https://lumen.laravel.com/docs/5.2/errors)
112-
- [Laravel](https://laravel.com/docs/5.4/errors) ([Example](https://stackoverflow.com/a/51790656/1856778))
113-
116+
- [Symfony](https://symfony.com/doc/current/logging.html) ([Example](https://github.com/maxbanton/cwh/issues/10#issuecomment-296173601))
117+
- [Laravel](https://laravel.com/docs/12.x/logging) ([Example](https://stackoverflow.com/a/51790656/1856778))
118+
114119
[And many others](https://github.com/Seldaek/monolog#framework-integrations)
120+
121+
## Migrating from 2.x to 3.x
122+
123+
3.x is a breaking release that drops Monolog 2 and PHP 7.x support. The constructor parameter order, names, and defaults are preserved — existing Symfony YAML and Laravel `with`/`handler_with` configs continue to work after the platform upgrades below.
124+
125+
**Required changes:**
126+
- Bump PHP to 8.1 or newer.
127+
- Bump Monolog to 3.x.
128+
- The `Monolog\Logger::DEBUG` (and other) constants were removed in Monolog 3. Use `Monolog\Level::Debug` instead — `int|string|Level` are all accepted by the `$level` constructor argument.
129+
- Symfony service definitions referencing `!php/const Monolog\Logger::WARNING` must change to `!php/const Monolog\Level::Warning`.
130+
- Laravel channels using `'level' => 'warning'` (string form) keep working unchanged.
131+
132+
**New (optional):**
133+
- A 10th constructor argument `$createStream` (default `true`). Set to `false` to skip `DescribeLogStreams`/`CreateLogStream` for pre-provisioned streams; lets you drop those IAM permissions.
115134

116135
# AWS IAM needed permissions
117136
if you prefer to use a separate programmatic IAM user (recommended) or want to define a policy, make sure following permissions are included:
@@ -122,7 +141,9 @@ if you prefer to use a separate programmatic IAM user (recommended) or want to d
122141
1. `DescribeLogStreams` [aws docs](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DescribeLogStreams.html)
123142
1. `DescribeLogGroups` [aws docs](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DescribeLogGroups.html)
124143

125-
When setting the `$createGroup` argument to `false`, permissions `DescribeLogGroups` and `CreateLogGroup` can be omitted
144+
When setting the `$createGroup` argument to `false`, permissions `DescribeLogGroups` and `CreateLogGroup` can be omitted.
145+
146+
When setting the `$createStream` argument to `false`, permissions `DescribeLogStreams` and `CreateLogStream` can be omitted. Use this when the log stream is provisioned out of band (e.g. via Terraform). If the stream does not exist at runtime, `PutLogEvents` will fail with `ResourceNotFoundException`.
126147

127148
## AWS IAM Policy full json example
128149
```json

compose.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
11
services:
2+
php81:
3+
build:
4+
context: .
5+
dockerfile: docker/Dockerfile
6+
args:
7+
PHP_VERSION: '8.1'
8+
working_dir: /app
9+
volumes:
10+
- .:/app
11+
- composer-cache:/tmp/composer
12+
- vendor-81:/app/vendor
13+
214
php82:
315
build:
416
context: .
@@ -49,6 +61,7 @@ services:
4961

5062
volumes:
5163
composer-cache:
64+
vendor-81:
5265
vendor-82:
5366
vendor-83:
5467
vendor-84:

composer.json

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,22 @@
2121
"source": "https://github.com/maxbanton/cwh"
2222
},
2323
"require": {
24-
"php": "^7.2 || ^8",
25-
"monolog/monolog": "^2.0",
26-
"aws/aws-sdk-php": "^3.18"
24+
"php": "^8.1",
25+
"aws/aws-sdk-php": "^3.0",
26+
"monolog/monolog": "^3.0"
2727
},
2828
"require-dev": {
29-
"phpunit/phpunit": "^8.5 || ^9.4",
30-
"squizlabs/php_codesniffer": "^3.5"
29+
"phpstan/phpstan": "^1.11",
30+
"phpunit/phpunit": "^10.5 || ^11.0",
31+
"squizlabs/php_codesniffer": "^3.10"
3132
},
3233
"suggest": {
3334
"maxbanton/dd": "Minimalistic dump-and-die function for easy debugging"
3435
},
3536
"config": {
36-
"preferred-install": "dist"
37+
"allow-plugins": {},
38+
"preferred-install": "dist",
39+
"sort-packages": true
3740
},
3841
"autoload": {
3942
"psr-4": {

phpstan.neon.dist

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
parameters:
2+
level: 8
3+
paths:
4+
- src
5+
treatPhpDocTypesAsCertain: false
6+
ignoreErrors:
7+
# User-facing $level accepts int|string|Level for ergonomics.
8+
# Monolog\Logger::toMonologLevel() narrows internally; broader type is intentional.
9+
-
10+
message: '#Parameter \#1 \$level of static method Monolog\\Logger::toMonologLevel\(\) expects.*int\|Monolog\\Level\|string given\.#'
11+
path: src/Handler/CloudWatch.php

phpunit.xml.dist

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3-
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
4-
backupGlobals="false"
5-
backupStaticAttributes="false"
6-
bootstrap="vendor/autoload.php"
7-
colors="true"
8-
convertErrorsToExceptions="true"
9-
convertNoticesToExceptions="true"
10-
convertWarningsToExceptions="true"
11-
processIsolation="false"
12-
stopOnFailure="false">
13-
<coverage>
14-
<include>
15-
<directory>src</directory>
16-
</include>
17-
</coverage>
18-
<testsuites>
19-
<testsuite name="Handler Test Suite">
20-
<directory suffix="Test.php">./tests/</directory>
21-
</testsuite>
22-
</testsuites>
3+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
4+
bootstrap="vendor/autoload.php"
5+
colors="true"
6+
backupGlobals="false"
7+
backupStaticProperties="false"
8+
processIsolation="false"
9+
stopOnFailure="false">
10+
<testsuites>
11+
<testsuite name="Handler Test Suite">
12+
<directory suffix="Test.php">./tests/</directory>
13+
</testsuite>
14+
</testsuites>
15+
<source>
16+
<include>
17+
<directory>src</directory>
18+
</include>
19+
</source>
2320
</phpunit>

0 commit comments

Comments
 (0)