| 199 |
lars |
1 |
<?php namespace Clockwork\DataSource;
|
|
|
2 |
|
|
|
3 |
use Clockwork\Helpers\Serializer;
|
|
|
4 |
use Clockwork\Helpers\StackTrace;
|
|
|
5 |
use Clockwork\Request\Request;
|
|
|
6 |
|
|
|
7 |
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
|
|
|
8 |
|
|
|
9 |
// Data source for Laravel cache component, provides cache queries and stats
|
|
|
10 |
class LaravelCacheDataSource extends DataSource
|
|
|
11 |
{
|
|
|
12 |
// Event dispatcher instance
|
|
|
13 |
protected $eventDispatcher;
|
|
|
14 |
|
|
|
15 |
// Executed cache queries
|
|
|
16 |
protected $queries = [];
|
|
|
17 |
|
|
|
18 |
// Query counts by type
|
|
|
19 |
protected $count = [
|
|
|
20 |
'read' => 0, 'hit' => 0, 'write' => 0, 'delete' => 0
|
|
|
21 |
];
|
|
|
22 |
|
|
|
23 |
// Whether we are collecting cache queries or stats only
|
|
|
24 |
protected $collectQueries = true;
|
|
|
25 |
|
|
|
26 |
// Whether we are collecting values from cache queries
|
|
|
27 |
protected $collectValues = true;
|
|
|
28 |
|
|
|
29 |
// Create a new data source instance, takes an event dispatcher and additional options as argument
|
|
|
30 |
public function __construct(EventDispatcher $eventDispatcher, $collectQueries = true, $collectValues = true)
|
|
|
31 |
{
|
|
|
32 |
$this->eventDispatcher = $eventDispatcher;
|
|
|
33 |
|
|
|
34 |
$this->collectQueries = $collectQueries;
|
|
|
35 |
$this->collectValues = $collectValues;
|
|
|
36 |
}
|
|
|
37 |
|
|
|
38 |
// Adds cache queries and stats to the request
|
|
|
39 |
public function resolve(Request $request)
|
|
|
40 |
{
|
|
|
41 |
$request->cacheQueries = array_merge($request->cacheQueries, $this->queries);
|
|
|
42 |
|
|
|
43 |
$request->cacheReads += $this->count['read'];
|
|
|
44 |
$request->cacheHits += $this->count['hit'];
|
|
|
45 |
$request->cacheWrites += $this->count['write'];
|
|
|
46 |
$request->cacheDeletes += $this->count['delete'];
|
|
|
47 |
|
|
|
48 |
return $request;
|
|
|
49 |
}
|
|
|
50 |
|
|
|
51 |
// Reset the data source to an empty state, clearing any collected data
|
|
|
52 |
public function reset()
|
|
|
53 |
{
|
|
|
54 |
$this->queries = [];
|
|
|
55 |
|
|
|
56 |
$this->count = [
|
|
|
57 |
'read' => 0, 'hit' => 0, 'write' => 0, 'delete' => 0
|
|
|
58 |
];
|
|
|
59 |
}
|
|
|
60 |
|
|
|
61 |
// Start listening to cache events
|
|
|
62 |
public function listenToEvents()
|
|
|
63 |
{
|
|
|
64 |
if (class_exists(\Illuminate\Cache\Events\CacheHit::class)) {
|
|
|
65 |
$this->eventDispatcher->listen(\Illuminate\Cache\Events\CacheHit::class, function ($event) {
|
|
|
66 |
$this->registerQuery([ 'type' => 'hit', 'key' => $event->key, 'value' => $event->value ]);
|
|
|
67 |
});
|
|
|
68 |
$this->eventDispatcher->listen(\Illuminate\Cache\Events\CacheMissed::class, function ($event) {
|
|
|
69 |
$this->registerQuery([ 'type' => 'miss', 'key' => $event->key ]);
|
|
|
70 |
});
|
|
|
71 |
$this->eventDispatcher->listen(\Illuminate\Cache\Events\KeyWritten::class, function ($event) {
|
|
|
72 |
$this->registerQuery([
|
|
|
73 |
'type' => 'write', 'key' => $event->key, 'value' => $event->value,
|
|
|
74 |
'expiration' => property_exists($event, 'seconds') ? $event->seconds : $event->minutes * 60
|
|
|
75 |
]);
|
|
|
76 |
});
|
|
|
77 |
$this->eventDispatcher->listen(\Illuminate\Cache\Events\KeyForgotten::class, function ($event) {
|
|
|
78 |
$this->registerQuery([ 'type' => 'delete', 'key' => $event->key ]);
|
|
|
79 |
});
|
|
|
80 |
} else {
|
|
|
81 |
// legacy Laravel 5.1 style events
|
|
|
82 |
$this->eventDispatcher->listen('cache.hit', function ($key, $value) {
|
|
|
83 |
$this->registerQuery([ 'type' => 'hit', 'key' => $key, 'value' => $value ]);
|
|
|
84 |
});
|
|
|
85 |
$this->eventDispatcher->listen('cache.missed', function ($key) {
|
|
|
86 |
$this->registerQuery([ 'type' => 'miss', 'key' => $key ]);
|
|
|
87 |
});
|
|
|
88 |
$this->eventDispatcher->listen('cache.write', function ($key, $value, $minutes) {
|
|
|
89 |
$this->registerQuery([
|
|
|
90 |
'type' => 'write', 'key' => $key, 'value' => $value, 'expiration' => $minutes * 60
|
|
|
91 |
]);
|
|
|
92 |
});
|
|
|
93 |
$this->eventDispatcher->listen('cache.delete', function ($key) {
|
|
|
94 |
$this->registerQuery([ 'type' => 'delete', 'key' => $key ]);
|
|
|
95 |
});
|
|
|
96 |
}
|
|
|
97 |
}
|
|
|
98 |
|
|
|
99 |
// Collect an executed query
|
|
|
100 |
protected function registerQuery(array $query)
|
|
|
101 |
{
|
|
|
102 |
$trace = StackTrace::get()->resolveViewName();
|
|
|
103 |
|
|
|
104 |
$record = [
|
|
|
105 |
'type' => $query['type'],
|
|
|
106 |
'key' => $query['key'],
|
|
|
107 |
'time' => microtime(true),
|
|
|
108 |
'connection' => null,
|
|
|
109 |
'trace' => (new Serializer)->trace($trace)
|
|
|
110 |
];
|
|
|
111 |
|
|
|
112 |
if ($this->collectValues && isset($query['value'])) {
|
|
|
113 |
$record['value'] = (new Serializer)->normalize($query['value']);
|
|
|
114 |
}
|
|
|
115 |
|
|
|
116 |
$this->incrementQueryCount($record);
|
|
|
117 |
|
|
|
118 |
if ($this->collectQueries && $this->passesFilters([ $record ])) {
|
|
|
119 |
$this->queries[] = $record;
|
|
|
120 |
}
|
|
|
121 |
}
|
|
|
122 |
|
|
|
123 |
// Increment query counts for collected query
|
|
|
124 |
protected function incrementQueryCount($query)
|
|
|
125 |
{
|
|
|
126 |
if ($query['type'] == 'write') {
|
|
|
127 |
$this->count['write']++;
|
|
|
128 |
} elseif ($query['type'] == 'delete') {
|
|
|
129 |
$this->count['delete']++;
|
|
|
130 |
} else {
|
|
|
131 |
$this->count['read']++;
|
|
|
132 |
|
|
|
133 |
if ($query['type'] == 'hit') {
|
|
|
134 |
$this->count['hit']++;
|
|
|
135 |
}
|
|
|
136 |
}
|
|
|
137 |
}
|
|
|
138 |
}
|