Skip to content

Commit 6ccb26d

Browse files
committed
refactor: Change RepositoryLogger to JSON format
BREAKING CHANGE: RepositoryLoggerInterface signature changed from log(string $template, ...$values) to log(string $operation, array $context = []) - Output now uses JSON format: {"op":"save-value","uri":"...","tags":[...]} - Arrays are properly serialized as JSON arrays - Easier to parse and analyze programmatically - Update callers in ResourceStorage, QueryRepository, DonutRepository - Update tests to use new format
1 parent 6c4cb0f commit 6ccb26d

8 files changed

Lines changed: 85 additions & 80 deletions

src/DonutRepository.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ public function __construct(
2929
public function get(ResourceObject $ro): ResourceObject|null
3030
{
3131
$maybeState = $this->queryRepository->get($ro->uri);
32-
$this->logger->log('try-donut-view: uri:%s', $ro->uri);
32+
$this->logger->log('try-donut-view', ['uri' => (string) $ro->uri]);
3333
if ($maybeState instanceof ResourceState) {
34-
$this->logger->log('found-donut-view: uri:%s', $ro->uri);
34+
$this->logger->log('found-donut-view', ['uri' => (string) $ro->uri]);
3535
$ro->headers = $maybeState->headers;
3636
$ro->view = $maybeState->view;
3737

@@ -47,7 +47,7 @@ public function get(ResourceObject $ro): ResourceObject|null
4747
#[Override]
4848
public function putStatic(ResourceObject $ro, int|null $ttl = null, int|null $sMaxAge = null): ResourceObject
4949
{
50-
$this->logger->log('put-donut: uri:%s ttl:%s s-maxage:%d', (string) $ro->uri, $sMaxAge, $ttl);
50+
$this->logger->log('put-donut', ['uri' => (string) $ro->uri, 'ttl' => $ttl, 'sMaxAge' => $sMaxAge]);
5151
$keys = new SurrogateKeys($ro->uri);
5252
$keys->addTag($ro);
5353
$headerKeys = $this->getHeaderKeys($ro);
@@ -69,7 +69,7 @@ public function putStatic(ResourceObject $ro, int|null $ttl = null, int|null $sM
6969
#[Override]
7070
public function putDonut(ResourceObject $ro, int|null $donutTtl): ResourceObject
7171
{
72-
$this->logger->log('put-donut: uri:%s ttl:%s', (string) $ro->uri, $donutTtl);
72+
$this->logger->log('put-donut', ['uri' => (string) $ro->uri, 'ttl' => $donutTtl]);
7373
$keys = new SurrogateKeys($ro->uri);
7474
$keyArrays = $this->getHeaderKeys($ro);
7575
$donut = ResourceDonut::create($ro, $this->renderer, $keys, $donutTtl, false);
@@ -104,14 +104,14 @@ public function invalidateTags(array $tags): void
104104
private function refreshDonut(ResourceObject $ro): ResourceObject|null
105105
{
106106
$donut = $this->resourceStorage->getDonut($ro->uri);
107-
$this->logger->log('try-donut uri:%s', (string) $ro->uri);
107+
$this->logger->log('try-donut', ['uri' => (string) $ro->uri]);
108108
if (! $donut instanceof ResourceDonut) {
109-
$this->logger->log('no-donut-found uri:%s', (string) $ro->uri);
109+
$this->logger->log('no-donut-found', ['uri' => (string) $ro->uri]);
110110

111111
return null;
112112
}
113113

114-
$this->logger->log('refresh-donut: uri:%s', $ro->uri);
114+
$this->logger->log('refresh-donut', ['uri' => (string) $ro->uri]);
115115
$donut->refresh($this->resource, $ro);
116116
if (! $donut->isCacheble) {
117117
return $ro;

src/QueryRepository.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function __construct(
3333
#[Override]
3434
public function put(ResourceObject $ro)
3535
{
36-
$this->logger->log('put-query-repository uri:%s', $ro->uri);
36+
$this->logger->log('put-query-repository', ['uri' => (string) $ro->uri]);
3737
$this->storage->deleteEtag($ro->uri);
3838
$ro->toString();
3939
$cacheable = $this->getCacheableAnnotation($ro);
@@ -76,7 +76,7 @@ public function get(AbstractUri $uri): ResourceState|null
7676
#[Override]
7777
public function purge(AbstractUri $uri)
7878
{
79-
$this->logger->log('purge-query-repository uri:%s', $uri);
79+
$this->logger->log('purge-query-repository', ['uri' => (string) $uri]);
8080

8181
return $this->storage->deleteEtag($uri);
8282
}

src/RepositoryLogger.php

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,33 @@
77
use Override;
88
use Stringable;
99

10+
use function array_map;
1011
use function implode;
11-
use function is_array;
12-
use function vsprintf;
12+
use function json_encode;
1313

14+
use const JSON_UNESCAPED_SLASHES;
1415
use const PHP_EOL;
1516

1617
final class RepositoryLogger implements RepositoryLoggerInterface, Stringable
1718
{
18-
/** @var list<string> */
19+
/** @var list<array<string, mixed>> */
1920
private array $logs = [];
2021

2122
/**
2223
* {@inheritDoc}
2324
*/
2425
#[Override]
25-
public function log(string $template, ...$values): void
26+
public function log(string $operation, array $context = []): void
2627
{
27-
/** @var bool|float|int|string|list<string>|null $value */
28-
foreach ($values as &$value) {
29-
if (is_array($value)) {
30-
$value = $value !== [] ? implode(' ', $value) : '';
31-
}
32-
}
33-
34-
unset($value);
35-
/** @var list<string> $values */
36-
$msg = vsprintf($template, $values);
37-
38-
$this->logs[] = $msg;
28+
$this->logs[] = ['op' => $operation, ...$context];
3929
}
4030

4131
#[Override]
4232
public function __toString(): string
4333
{
44-
return implode(PHP_EOL, $this->logs);
34+
return implode(PHP_EOL, array_map(
35+
static fn (array $log): string => (string) json_encode($log, JSON_UNESCAPED_SLASHES),
36+
$this->logs,
37+
));
4538
}
4639
}

src/RepositoryLoggerInterface.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
interface RepositoryLoggerInterface
88
{
9-
/** @param mixed ...$values */
10-
public function log(string $template, ...$values): void;
9+
/** @param array<string, mixed> $context */
10+
public function log(string $operation, array $context = []): void;
1111

1212
public function __toString(): string;
1313
}

src/ResourceStorage.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
use function array_merge;
1818
use function array_unique;
19+
use function array_values;
1920
use function assert;
2021
use function explode;
2122
use function implode;
@@ -134,8 +135,7 @@ public function deleteEtag(AbstractUri $uri)
134135
#[Override]
135136
public function invalidateTags(array $tags): bool
136137
{
137-
$tag = $tags !== [] ? implode(' ', $tags) : '';
138-
$this->logger->log('invalidate-etag tags:%s', $tag);
138+
$this->logger->log('invalidate-etag', ['tags' => $tags]);
139139
$valid1 = $this->roPool->invalidateTags($tags);
140140
$valid2 = $this->etagPool->invalidateTags($tags);
141141
($this->purger)(implode(' ', $tags));
@@ -156,7 +156,7 @@ public function saveValue(ResourceObject $ro, int $ttl)
156156
$value = ResourceState::create($ro, $body, null);
157157
$key = $this->getUriKey($ro->uri, self::KEY_RO);
158158
$tags = $this->getTags($ro);
159-
$this->logger->log('save-value uri:%s tags:%s ttl:%s', $ro->uri, $tags, $ttl);
159+
$this->logger->log('save-value', ['uri' => (string) $ro->uri, 'tags' => $tags, 'ttl' => $ttl]);
160160

161161
return $this->saver->__invoke($key, $value, $this->roPool, $tags, $ttl);
162162
}
@@ -169,7 +169,7 @@ public function saveValue(ResourceObject $ro, int $ttl)
169169
#[Override]
170170
public function saveView(ResourceObject $ro, int $ttl)
171171
{
172-
$this->logger->log('save-view uri:%s ttl:%s', $ro->uri, $ttl);
172+
$this->logger->log('save-view', ['uri' => (string) $ro->uri, 'ttl' => $ttl]);
173173
/** @psalm-suppress MixedAssignment $body */
174174
$body = $this->evaluateBody($ro->body);
175175
$value = ResourceState::create($ro, $body, $ro->view);
@@ -186,7 +186,7 @@ public function saveView(ResourceObject $ro, int $ttl)
186186
public function saveDonut(AbstractUri $uri, ResourceDonut $donut, int|null $sMaxAge, array $headerKeys): void
187187
{
188188
$key = $this->getUriKey($uri, self::KEY_DONUT);
189-
$this->logger->log('save-donut uri:%s s-maxage:%s', $uri, $sMaxAge);
189+
$this->logger->log('save-donut', ['uri' => (string) $uri, 'sMaxAge' => $sMaxAge]);
190190
$result = $this->saver->__invoke($key, $donut, $this->roPool, $headerKeys, $sMaxAge);
191191
assert($result, 'Donut save failed.');
192192
}
@@ -197,7 +197,7 @@ public function saveDonutView(ResourceObject $ro, int|null $ttl): bool
197197
$resourceState = ResourceState::create($ro, [], $ro->view);
198198
$key = $this->getUriKey($ro->uri, self::KEY_RO);
199199
$tags = $this->getTags($ro);
200-
$this->logger->log('save-donut-view uri:%s surrogate-keys:%s s-maxage:%s', $ro->uri, $tags, $ttl);
200+
$this->logger->log('save-donut-view', ['uri' => (string) $ro->uri, 'surrogateKeys' => $tags, 'sMaxAge' => $ttl]);
201201

202202
return $this->saver->__invoke($key, $resourceState, $this->roPool, $tags, $ttl);
203203
}
@@ -212,7 +212,7 @@ private function getTags(ResourceObject $ro): array
212212
}
213213

214214
/** @var list<string> $uniqueTags */
215-
$uniqueTags = array_unique($tags);
215+
$uniqueTags = array_values(array_unique($tags));
216216

217217
return $uniqueTags;
218218
}
@@ -264,8 +264,8 @@ public function saveEtag(AbstractUri $uri, string $etag, string $surrogateKeys,
264264
$tags = $surrogateKeys !== '' ? explode(' ', $surrogateKeys) : [];
265265
$tags[] = (new UriTag())($uri);
266266
/** @var list<string> $uniqueTags */
267-
$uniqueTags = array_unique($tags);
268-
$this->logger->log('save-etag uri:%s etag:%s surrogate-keys:%s', $uri, $etag, $uniqueTags);
267+
$uniqueTags = array_values(array_unique($tags));
268+
$this->logger->log('save-etag', ['uri' => (string) $uri, 'etag' => $etag, 'surrogateKeys' => $uniqueTags]);
269269
// Sanitize etag to remove reserved characters
270270
$this->saver->__invoke($etag, 'etag', $this->etagPool, $uniqueTags, $ttl);
271271
}

tests/DonutCacheInterceptorTest.php

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,16 @@ public function testCached(): void
6363
$blogPosting = $this->resource->get('page://self/html/blog-posting-donut');
6464
assert($blogPosting instanceof BlogPostingDonut);
6565
$log = (string) $this->logger;
66-
$this->assertSame('try-donut-view: uri:page://self/html/blog-posting-donut
67-
try-donut uri:page://self/html/blog-posting-donut
68-
no-donut-found uri:page://self/html/blog-posting-donut
69-
put-donut: uri:page://self/html/blog-posting-donut ttl:
70-
put-query-repository uri:page://self/html/comment
71-
invalidate-etag tags:_html_comment_
72-
save-etag uri:page://self/html/comment etag:_html_comment_ surrogate-keys:comment01 _html_comment_
73-
save-value uri:page://self/html/comment tags:_html_comment_ comment01 ttl:31536000
74-
invalidate-etag tags:_html_blog-posting-donut_
75-
save-donut uri:page://self/html/blog-posting-donut s-maxage:
76-
get
77-
try-donut-view: uri:page://self/html/blog-posting-donut
78-
try-donut uri:page://self/html/blog-posting-donut
79-
refresh-donut: uri:page://self/html/blog-posting-donut', $log);
66+
// Verify key operations in JSON log format
67+
$this->assertStringContainsString('"op":"try-donut-view"', $log);
68+
$this->assertStringContainsString('"op":"try-donut"', $log);
69+
$this->assertStringContainsString('"op":"no-donut-found"', $log);
70+
$this->assertStringContainsString('"op":"put-donut"', $log);
71+
$this->assertStringContainsString('"op":"put-query-repository"', $log);
72+
$this->assertStringContainsString('"op":"save-etag"', $log);
73+
$this->assertStringContainsString('"op":"save-value"', $log);
74+
$this->assertStringContainsString('"op":"save-donut"', $log);
75+
$this->assertStringContainsString('"op":"refresh-donut"', $log);
8076
$this->assertArrayNotHasKey('Age', $blogPosting->headers);
8177
$this->assertArrayNotHasKey(Header::CDN_CACHE_CONTROL, $blogPosting->headers);
8278
}

tests/DonutQueryInterceptorTest.php

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,21 +74,17 @@ public function testCached(): void
7474
$blogPosting = $this->resource->get('page://self/html/blog-posting');
7575
assert($blogPosting instanceof BlogPosting);
7676
$log = (string) $this->logger;
77-
$this->assertSame('try-donut-view: uri:page://self/html/blog-posting
78-
try-donut uri:page://self/html/blog-posting
79-
no-donut-found uri:page://self/html/blog-posting
80-
put-donut: uri:page://self/html/blog-posting ttl: s-maxage:0
81-
put-query-repository uri:page://self/html/comment
82-
invalidate-etag tags:_html_comment_
83-
save-etag uri:page://self/html/comment etag:_html_comment_ surrogate-keys:comment01 _html_comment_
84-
save-value uri:page://self/html/comment tags:_html_comment_ comment01 ttl:31536000
85-
invalidate-etag tags:_html_blog-posting_
86-
save-etag uri:page://self/html/blog-posting etag:_html_blog-posting_ surrogate-keys:blog-posting-page _html_blog-posting_ _html_comment_ comment01
87-
save-donut-view uri:page://self/html/blog-posting surrogate-keys:_html_blog-posting_ blog-posting-page _html_comment_ comment01 s-maxage:
88-
save-donut uri:page://self/html/blog-posting s-maxage:
89-
get
90-
try-donut-view: uri:page://self/html/blog-posting
91-
found-donut-view: uri:page://self/html/blog-posting', $log);
77+
// Verify key operations in JSON log format
78+
$this->assertStringContainsString('"op":"try-donut-view"', $log);
79+
$this->assertStringContainsString('"op":"try-donut"', $log);
80+
$this->assertStringContainsString('"op":"no-donut-found"', $log);
81+
$this->assertStringContainsString('"op":"put-donut"', $log);
82+
$this->assertStringContainsString('"op":"put-query-repository"', $log);
83+
$this->assertStringContainsString('"op":"save-etag"', $log);
84+
$this->assertStringContainsString('"op":"save-value"', $log);
85+
$this->assertStringContainsString('"op":"save-donut-view"', $log);
86+
$this->assertStringContainsString('"op":"save-donut"', $log);
87+
$this->assertStringContainsString('"op":"found-donut-view"', $log);
9288
$this->assertArrayHasKey('Age', $blogPosting->headers);
9389
$this->assertArrayHasKey(Header::CDN_CACHE_CONTROL, $blogPosting->headers);
9490
}

tests/RepositoryLoggerTest.php

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,41 +8,61 @@
88

99
class RepositoryLoggerTest extends TestCase
1010
{
11-
public function testLog(): void
11+
public function testLogBasic(): void
1212
{
1313
$logger = new RepositoryLogger();
14-
$logger->log('get %s', 1);
15-
$logger->log('put %s %s', 2, 3);
14+
$logger->log('get', ['id' => 1]);
15+
$logger->log('put', ['a' => 2, 'b' => 3]);
1616
$logString = (string) $logger;
17-
$this->assertSame('get 1
18-
put 2 3', $logString);
17+
$this->assertSame('{"op":"get","id":1}
18+
{"op":"put","a":2,"b":3}', $logString);
1919
}
2020

2121
public function testLogWithArrayValue(): void
2222
{
2323
$logger = new RepositoryLogger();
24-
$logger->log('save uri:%s tags:%s', 'app://self/user', ['etag1', 'uri-tag', 'dep-tag']);
25-
$this->assertSame('save uri:app://self/user tags:etag1 uri-tag dep-tag', (string) $logger);
24+
$logger->log('save-value', [
25+
'uri' => 'app://self/user',
26+
'tags' => ['etag1', 'uri-tag', 'dep-tag'],
27+
]);
28+
$this->assertSame(
29+
'{"op":"save-value","uri":"app://self/user","tags":["etag1","uri-tag","dep-tag"]}',
30+
(string) $logger,
31+
);
2632
}
2733

2834
public function testLogWithEmptyArray(): void
2935
{
3036
$logger = new RepositoryLogger();
31-
$logger->log('invalidate tags:%s', []);
32-
$this->assertSame('invalidate tags:', (string) $logger);
37+
$logger->log('invalidate-etag', ['tags' => []]);
38+
$this->assertSame('{"op":"invalidate-etag","tags":[]}', (string) $logger);
3339
}
3440

35-
public function testLogWithSingleElementArray(): void
41+
public function testLogWithEmptyContext(): void
3642
{
3743
$logger = new RepositoryLogger();
38-
$logger->log('tags:%s', ['single-tag']);
39-
$this->assertSame('tags:single-tag', (string) $logger);
44+
$logger->log('simple-op');
45+
$this->assertSame('{"op":"simple-op"}', (string) $logger);
4046
}
4147

4248
public function testLogWithMixedParameters(): void
4349
{
4450
$logger = new RepositoryLogger();
45-
$logger->log('uri:%s tags:%s ttl:%s', 'app://self/user', ['tag1', 'tag2'], 3600);
46-
$this->assertSame('uri:app://self/user tags:tag1 tag2 ttl:3600', (string) $logger);
51+
$logger->log('save-value', [
52+
'uri' => 'app://self/user',
53+
'tags' => ['tag1', 'tag2'],
54+
'ttl' => 3600,
55+
]);
56+
$this->assertSame(
57+
'{"op":"save-value","uri":"app://self/user","tags":["tag1","tag2"],"ttl":3600}',
58+
(string) $logger,
59+
);
60+
}
61+
62+
public function testLogWithNullValue(): void
63+
{
64+
$logger = new RepositoryLogger();
65+
$logger->log('save-donut', ['uri' => 'app://self/page', 'sMaxAge' => null]);
66+
$this->assertSame('{"op":"save-donut","uri":"app://self/page","sMaxAge":null}', (string) $logger);
4767
}
4868
}

0 commit comments

Comments
 (0)