Skip to content

Commit

Permalink
Merge pull request #16 from okvpn/feat/dd-dsn
Browse files Browse the repository at this point in the history
Allow to use multiply DD clients with DSN config
  • Loading branch information
vtsykun authored Jan 7, 2024
2 parents f225b9c + 21054bb commit 25efdba
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 16 deletions.
41 changes: 30 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,35 @@ return [

```
okvpn_datadog:
profiling: true
namespace: app # You app namespace for custome metric app.*, see https://docs.datadoghq.com/developers/metrics/#naming-metrics
clients:
default: 'datadog://127.0.0.1/namespase'
## More clients
i2pd_client: 'datadog://10.10.1.1:8125/app?tags=tg1,tg2'
'null': null://null
mock: mock://mock
dns: '%env(DD_CLIENT)%'
```

Where env var looks like:
```
DD_CLIENT=datadog://127.0.0.1:8125/app1?tags=tg1,tg2
```

Access to client via DIC:

```php
class FeedController extends Controller
{
// Inject via arg for Symfony 4+
#[Route(path: '/', name: 'feeds')]
public function feedsAction(DogStatsInterface $dogStats, DogStatsInterface $i2pdClient): Response
{
$dogStats->decrement('feed');

return $this->render('feed/feeds.html.twig');
}
}
```

## Custom metrics that provided by OkvpnDatadogBundle
Expand All @@ -59,15 +86,7 @@ Where `app` metrics namespace.

## Configuration

And create config `config/packages/datadog.yml` with

```
okvpn_datadog:
namespace: app
port: 8125
```

A more complex setup look like this `config.yml`:
A more complex setup look like this `config/packages/ddog.yml`:

```
Expand Down
100 changes: 98 additions & 2 deletions src/Client/DatadogDns.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,106 @@

namespace Okvpn\Bundle\DatadogBundle\Client;

class DatadogDns
final class DatadogDns
{
public static function parser(string $dsn): array
private string $originalDsn;
private string $scheme;
private string $host;
private int $port;
private string $namespace;
private array $tags = [];

public function __construct(string $dsn)
{
$this->parser($dsn);
}

public static function fromString(string $dsn): self
{
return new DatadogDns($dsn);
}

private function parser(string $dsn): void
{
$this->originalDsn = $dsn;

if (false === $dsn = parse_url($dsn)) {
throw new \InvalidArgumentException('The datadog DSN is invalid.');
}

if (!isset($dsn['scheme'])) {
throw new \InvalidArgumentException('The datadog DSN must contain a scheme.');
}

$this->scheme = $dsn['scheme'];
$this->host = $dsn['host'] ?? '127.0.0.1';
$this->port = $dsn['port'] ?? 8125;
$this->namespace = str_replace('/', '', $dsn['path'] ?? 'app');

if (isset($dsn['query'])) {
parse_str($dsn['query'], $query);
if (isset($query['tags'])) {
$this->tags = explode(',', $query['tags']);
}
}
}

/**
* @return string
*/
public function getOriginalDsn(): string
{
return $this->originalDsn;
}

/**
* @return string
*/
public function getScheme(): string
{
return $this->scheme;
}

/**
* @return string
*/
public function getHost(): string
{
return $this->host;
}

/**
* @return int
*/
public function getPort(): int
{
return $this->port;
}

/**
* @return string
*/
public function getNamespace(): string
{
return $this->namespace;
}

/**
* @return array
*/
public function getTags(): array
{
return $this->tags;
}

public function toArray(): array
{
return [
'scheme' => $this->getScheme(),
'namespace' => $this->getNamespace(),
'tags' => $this->getTags(),
'host' => $this->getHost(),
'port' => $this->getPort(),
];
}
}
22 changes: 22 additions & 0 deletions src/Client/DatadogFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,32 @@

class DatadogFactory implements DatadogFactoryInterface
{
protected static $clientFactories = [
'null' => NullDatadogClient::class,
'mock' => MockClient::class,
'datadog' => DatadogClient::class,
];

/**
* {@inheritdoc}
*/
public function createClient(array $options): DogStatsInterface
{
if (isset($options['dsn'])) {
$dsn = DatadogDns::fromString($options['dsn']);
$options = $dsn->toArray() + $options;
}

$scheme = $options['scheme'] ?? 'datadog';
if (!static::$clientFactories[$scheme]) {
throw new \InvalidArgumentException('The datadog DSN scheme "%s" does not exists. Allowed "%s"', $scheme, implode(",", static::$clientFactories));
}

return new static::$clientFactories[$scheme]($options);
}

public static function setClientFactory(string $alias, string $className): void
{
static::$clientFactories[$alias] = $className;
}
}
3 changes: 1 addition & 2 deletions src/DependencyInjection/CompilerPass/SqlLoggerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Reference;

class SqlLoggerPass implements CompilerPassInterface
Expand All @@ -34,7 +33,7 @@ public function process(ContainerBuilder $container): void
continue;
}
$loggerId = 'okvpn_datadog.sql_logger.' . $name;
$container->setDefinition($loggerId, class_exists(ChildDefinition::class) ? new ChildDefinition('okvpn_datadog.logger.sql') : new DefinitionDecorator('okvpn_datadog.logger.sql'));
$container->setDefinition($loggerId, new ChildDefinition('okvpn_datadog.logger.sql'));
$configuration = $container->getDefinition($configuration);
if ($configuration->hasMethodCall('setSQLLogger')) {
$chainLoggerId = 'doctrine.dbal.logger.chain.' . $name;
Expand Down
32 changes: 32 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Okvpn\Bundle\DatadogBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

Expand Down Expand Up @@ -74,6 +75,37 @@ public function getConfigTreeBuilder(): TreeBuilder
->defaultFalse()
->end();

$this->addClientsSection($rootNode);

return $treeBuilder;
}

private function addClientsSection(ArrayNodeDefinition $rootNode): void
{
$rootNode->children()
->arrayNode('clients')
->useAttributeAsKey('alias', false)
->beforeNormalization()
->always()
->then(static function ($v) {
if (is_iterable($v)) {
foreach ($v as $name => $client) {
if (is_string($client)) {
$client = ['dsn' => $client];
}
$client['alias'] = $name;
$v[$name] = $client;
}
}
return $v;
})
->end()
->arrayPrototype()
->children()
->scalarNode('alias')->isRequired()->end()
->scalarNode('dsn')->isRequired()->end()
->end()
->end()
->end();
}
}
26 changes: 26 additions & 0 deletions src/DependencyInjection/OkvpnDatadogExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@

namespace Okvpn\Bundle\DatadogBundle\DependencyInjection;

use Okvpn\Bundle\DatadogBundle\Client\DatadogFactoryInterface;
use Okvpn\Bundle\DatadogBundle\Client\DogStatsInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;

Expand All @@ -28,9 +32,22 @@ public function load(array $configs, ContainerBuilder $container): void
->replaceArgument(6, $config['dedup_keep_time']);
$container->getDefinition('okvpn_datadog.logger.artifact_storage')
->replaceArgument(0, $config['artifacts_path'] ?: $container->getParameter('kernel.logs_dir'));

$container->getDefinition('okvpn_datadog.client')
->replaceArgument(0, $config);

if (isset($config['clients'])) {
foreach ($config['clients'] as $client) {
$this->loadClient($container, $client);
}

if (isset($config['clients']['default'])) {
$container->removeDefinition('okvpn_datadog.client');
$container->setAlias('okvpn_datadog.client', 'okvpn_datadog.client.default')->setPublic(true);
$container->setAlias(DogStatsInterface::class, 'okvpn_datadog.client.default')->setPublic(true);
}
}

if (true === $config['profiling']) {
if (true === $config['doctrine']) {
$loader->load('sqllogger.yml');
Expand All @@ -42,6 +59,15 @@ public function load(array $configs, ContainerBuilder $container): void
$container->setParameter('okvpn_datadog.profiling', $config['profiling']);
}

protected function loadClient(ContainerBuilder $container, array $client)
{
$ddDef = new Definition(DogStatsInterface::class, [$client]);
$ddDef->setFactory([new Reference(DatadogFactoryInterface::class), 'createClient']);

$container->setDefinition($id = sprintf('okvpn_datadog.client.%s', $client['alias']), $ddDef);
$container->registerAliasForArgument($id, DogStatsInterface::class, $client['alias']);
}

protected function defaultHandlerExceptions(array $config): array
{
$config = $config['handle_exceptions'] ?? [];
Expand Down
8 changes: 7 additions & 1 deletion src/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@ services:
- null
- null

Okvpn\Bundle\DatadogBundle\Client\DatadogFactory: ~

Okvpn\Bundle\DatadogBundle\Client\DatadogFactoryInterface:
alias: Okvpn\Bundle\DatadogBundle\Client\DatadogFactory

okvpn_datadog.client:
class: Okvpn\Bundle\DatadogBundle\Client\DatadogClient
arguments: [~]
factory: ['@Okvpn\Bundle\DatadogBundle\Client\DatadogFactoryInterface', 'createClient']
arguments: [[]]
public: true

Okvpn\Bundle\DatadogBundle\Client\DogStatsInterface:
Expand Down

0 comments on commit 25efdba

Please sign in to comment.