Skip to content

Commit de587ad

Browse files
cosmastechLuke Kuzmish
andauthored
ExceptionCatchingDataDogClient (#14)
* safe dog * add override * Update ExceptionCatchingDatadogClient.php * clean up * readme --------- Co-authored-by: Luke Kuzmish <[email protected]>
1 parent 71f8b89 commit de587ad

File tree

5 files changed

+99
-19
lines changed

5 files changed

+99
-19
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ For a local development setup, you could just write the stats to a log. This wri
4747

4848
See [examples/log_datadog.php](examples/log_datadog.php) for how you might implement this.
4949

50+
### ExceptionCatchingDatadogClient
51+
This client will allow handling exceptions thrown when attempting to write data to DataDog.
52+
53+
See [examples/safe_datadog.php](examples/safe_datadog.php) for how to use this client.
54+
5055
### LeagueStatsDClientAdapter
5156
You can also write to an arbitrary statsd server by leveraging [PHP League's statsd package](https://github.com/thephpleague/statsd).
5257

examples/safe_datadog.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
require_once __DIR__ . "/../vendor/autoload.php";
4+
5+
// See instantiation parameters: https://docs.datadoghq.com/developers/dogstatsd/?code-lang=php&tab=hostagent#client-instantiation-parameters
6+
7+
// You will need Monolog installed to run this example.
8+
9+
$logger = new \Monolog\Logger('safe_datadog');
10+
$logger->pushHandler(new \Monolog\Handler\StreamHandler(__DIR__ . '/log_datadog.txt', \Monolog\Level::Debug));
11+
12+
$datadog = new \Cosmastech\StatsDClientAdapter\Clients\Datadog\ExceptionCatchingDatadogClient(
13+
[],
14+
static fn (\Throwable $t) => $logger->error('Exception: ' . $t->getMessage())
15+
);
16+
17+
$adapter = new \Cosmastech\StatsDClientAdapter\Adapters\Datadog\DatadogStatsDClientAdapter($datadog);
18+
19+
$adapter->increment("logins", 1, ["type" => "successful"], 1); // assume that this fails
20+
21+
// You should see a file named log_datadog.txt in this directory which will have stats
22+
// ex: [2024-07-08T23:59:18.880180+00:00] safe_datadog.ERROR: Exception: ErrorException: socket_sendto(): Unable to write to socket [111]: Connection refused in /var/www/vendor/datadog/php-datadogstatsd/src/DogStatsd.php:502

src/Adapters/Concerns/ConvertsStatTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ protected function convertStat(mixed $value): string|array
1515
{
1616
if (is_array($value)) {
1717
$convertedStats = [];
18-
foreach($value as $element) {
18+
foreach ($value as $element) {
1919
$convertedStats[] = $this->convertValueToString($element);
2020
}
2121

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace Cosmastech\StatsDClientAdapter\Clients\Datadog;
4+
5+
use Closure;
6+
use DataDog\DogStatsd;
7+
use Throwable;
8+
9+
class ExceptionCatchingDatadogClient extends DogStatsd
10+
{
11+
/**
12+
* The callback to execute when there is an exception flushing stats to DataDog.
13+
*
14+
* @var Closure(Throwable, mixed): void
15+
*/
16+
protected Closure $onExceptionCallback;
17+
18+
/**
19+
* @{inheritDoc}
20+
*
21+
* @param (Closure(\Throwable, mixed): void) $onExceptionCallback The callback to execute when there is an exception flushing stats to DataDog
22+
*/
23+
public function __construct(
24+
array $config,
25+
Closure $onExceptionCallback,
26+
) {
27+
parent::__construct($config);
28+
29+
$this->onExceptionCallback = $onExceptionCallback;
30+
}
31+
32+
/**
33+
* @param mixed $message
34+
* @return void
35+
*/
36+
#[\Override]
37+
public function report($message)
38+
{
39+
try {
40+
parent::report($message);
41+
} catch (Throwable $exception) {
42+
call_user_func($this->onExceptionCallback, $exception, $message);
43+
}
44+
}
45+
}

tests/Doubles/DogStatsDSpy.php

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,70 +34,78 @@ public function __construct()
3434

3535
/**
3636
* @inheritDoc
37+
* @param mixed $cardinality
3738
* @phpstan-ignore missingType.iterableValue
3839
*/
39-
public function timing($stat, $time, $sampleRate = 1.0, $tags = null)
40+
public function timing($stat, $time, $sampleRate = 1.0, $tags = null, $cardinality = null)
4041
{
41-
$this->timings[] = compact('stat', 'time', 'sampleRate', 'tags');
42+
$this->timings[] = compact('stat', 'time', 'sampleRate', 'tags', 'cardinality');
4243
}
4344

4445
/**
4546
* @inheritDoc
47+
* @param mixed $cardinality
4648
* @phpstan-ignore missingType.iterableValue
4749
*/
48-
public function gauge($stat, $value, $sampleRate = 1.0, $tags = null)
50+
public function gauge($stat, $value, $sampleRate = 1.0, $tags = null, $cardinality = null)
4951
{
50-
$this->gauges[] = compact('stat', 'value', 'sampleRate', 'tags');
52+
$this->gauges[] = compact('stat', 'value', 'sampleRate', 'tags', 'cardinality');
5153
}
5254

5355
/**
5456
* @inheritDoc
57+
* @param mixed $cardinality
5558
* @phpstan-ignore missingType.iterableValue
5659
*/
57-
public function histogram($stat, $value, $sampleRate = 1.0, $tags = null)
60+
public function histogram($stat, $value, $sampleRate = 1.0, $tags = null, $cardinality = null)
5861
{
59-
$this->histograms[] = compact('stat', 'value', 'sampleRate', 'tags');
62+
$this->histograms[] = compact('stat', 'value', 'sampleRate', 'tags', 'cardinality');
6063
}
6164

6265
/**
6366
* @inheritDoc
67+
* @param mixed $cardinality
6468
* @phpstan-ignore missingType.iterableValue
6569
*/
66-
public function distribution($stat, $value, $sampleRate = 1.0, $tags = null)
70+
public function distribution($stat, $value, $sampleRate = 1.0, $tags = null, $cardinality = null)
6771
{
68-
$this->distributions[] = compact('stat', 'value', 'sampleRate', 'tags');
72+
$this->distributions[] = compact('stat', 'value', 'sampleRate', 'tags', 'cardinality');
6973
}
7074

7175
/**
7276
* @inheritdoc
77+
* @param mixed $cardinality
7378
* @phpstan-ignore missingType.iterableValue
7479
*/
75-
public function set($stat, $value, $sampleRate = 1.0, $tags = null)
80+
public function set($stat, $value, $sampleRate = 1.0, $tags = null, $cardinality = null)
7681
{
77-
$this->sets[] = compact('stat', 'value', 'sampleRate', 'tags');
82+
$this->sets[] = compact('stat', 'value', 'sampleRate', 'tags', 'cardinality');
7883
}
7984

8085
/**
8186
* @inheritDoc
82-
* @param string|array<int, mixed> $stats
83-
* @param array<int, mixed>|string $tags
87+
* @param mixed $cardinality
88+
* @param string|array<int, mixed> $stats
89+
* @param array<int, mixed>|string $tags
8490
*/
8591
public function increment(
8692
$stats,
8793
$sampleRate = 1.0,
8894
$tags = null,
89-
$value = 1
95+
$value = 1,
96+
$cardinality = null
9097
) {
91-
$this->increments[] = compact('stats', 'value', 'sampleRate', 'tags');
98+
$this->increments[] = compact('stats', 'value', 'sampleRate', 'tags', 'cardinality');
9299
}
93100

94101
/**
95102
* @inheritdoc
96-
* @param string|array<int, mixed> $stats
97-
* @param array<int, mixed>|string $tags
103+
* @param string|array<int, mixed> $stats
104+
* @param array<int, mixed>|string $tags
105+
* @param mixed $cardinality
98106
*/
99-
public function decrement($stats, $sampleRate = 1.0, $tags = null, $value = -1)
107+
public function decrement($stats, $sampleRate = 1.0, $tags = null, $value = -1, $cardinality = null)
100108
{
101-
$this->decrements[] = compact('stats', 'value', 'sampleRate', 'tags');
109+
$this->decrements[] = compact('stats', 'value', 'sampleRate', 'tags', 'cardinality');
102110
}
103111
}

0 commit comments

Comments
 (0)