• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FriendsOfOpenTelemetry / opentelemetry-bundle / 13767573364

10 Mar 2025 02:47PM UTC coverage: 91.422% (+0.1%) from 91.295%
13767573364

push

github

gaelreyrol
feat(Instrumentation/Metrics): flush metrics on Console & Kernel TERMINATE events

49 of 50 new or added lines in 8 files covered. (98.0%)

2238 of 2448 relevant lines covered (91.42%)

35.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.33
/src/DependencyInjection/OpenTelemetryExtension.php
1
<?php
2

3
namespace FriendsOfOpenTelemetry\OpenTelemetryBundle\DependencyInjection;
4

5
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
6
use FriendsOfOpenTelemetry\OpenTelemetryBundle\Instrumentation\InstrumentationTypeEnum;
7
use Symfony\Bundle\TwigBundle\TwigBundle;
8
use Symfony\Component\Cache\CacheItem;
9
use Symfony\Component\Config\FileLocator;
10
use Symfony\Component\Console\Command\Command;
11
use Symfony\Component\DependencyInjection\ContainerBuilder;
12
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
13
use Symfony\Component\HttpClient\HttpClient;
14
use Symfony\Component\HttpKernel\DependencyInjection\ConfigurableExtension;
15
use Symfony\Component\Mailer\MailerInterface;
16
use Symfony\Component\Messenger\Envelope;
17

18
/**
19
 * @phpstan-type InstrumentationConfig array{
20
 *     type?: string,
21
 *     tracing: TracingInstrumentationConfig,
22
 *     metering: MeteringInstrumentationConfig,
23
 * }
24
 * @phpstan-type TracingInstrumentationConfig array{
25
 *     enabled: bool,
26
 *     tracer: ?string,
27
 *     exclude_paths?: string[],
28
 *     exclude_commands?: string[]
29
 * }
30
 * @phpstan-type MeteringInstrumentationConfig array{
31
 *     enabled: bool,
32
 *     meter: ?string,
33
 * }
34
 */
35
final class OpenTelemetryExtension extends ConfigurableExtension
36
{
37
    protected function loadInternal(array $mergedConfig, ContainerBuilder $container): void
38
    {
39
        $loader = new PhpFileLoader($container, new FileLocator(dirname(__DIR__).'/Resources/config'));
51✔
40
        $loader->load('services.php');
51✔
41
        $loader->load('services_transports.php');
51✔
42
        $loader->load('services_logs.php');
51✔
43
        $loader->load('services_metrics.php');
51✔
44
        $loader->load('services_traces.php');
51✔
45
        $loader->load('services_tracing_instrumentation.php');
51✔
46
        $loader->load('services_metering_instrumentation.php');
51✔
47

48
        $this->registerService($mergedConfig['service'], $container);
51✔
49
        $this->registerInstrumentation($mergedConfig['instrumentation'], $container);
51✔
50

51
        (new OpenTelemetryTracesExtension())($mergedConfig['traces'], $container);
51✔
52
        (new OpenTelemetryMetricsExtension())($mergedConfig['metrics'], $container);
48✔
53
        (new OpenTelemetryLogsExtension())($mergedConfig['logs'], $container);
45✔
54
    }
55

56
    /**
57
     * @param array{
58
     *     namespace: string,
59
     *     name: string,
60
     *     version: string,
61
     *     environment: string
62
     * } $config
63
     */
64
    private function registerService(array $config, ContainerBuilder $container): void
65
    {
66
        $container->setParameter('open_telemetry.service.namespace', $config['namespace']);
51✔
67
        $container->setParameter('open_telemetry.service.name', $config['name']);
51✔
68
        $container->setParameter('open_telemetry.service.version', $config['version']);
51✔
69
        $container->setParameter('open_telemetry.service.environment', $config['environment']);
51✔
70

71
        $container->getDefinition('open_telemetry.resource_info')
51✔
72
            ->setArguments([
51✔
73
                $config['namespace'],
51✔
74
                $config['name'],
51✔
75
                $config['version'],
51✔
76
                $config['environment'],
51✔
77
            ]);
51✔
78
    }
79

80
    /**
81
     * @param array{
82
     *     cache: InstrumentationConfig,
83
     *     console: InstrumentationConfig,
84
     *     doctrine: InstrumentationConfig,
85
     *     http_client: InstrumentationConfig,
86
     *     http_kernel: InstrumentationConfig,
87
     *     mailer: InstrumentationConfig,
88
     *     messenger: InstrumentationConfig,
89
     *     twig: InstrumentationConfig,
90
     * } $config
91
     */
92
    private function registerInstrumentation(array $config, ContainerBuilder $container): void
93
    {
94
        $this->registerCacheTracingInstrumentationConfiguration($container, $config['cache']);
51✔
95

96
        $this->registerConsoleTracingInstrumentationConfiguration($container, $config['console']);
51✔
97
        $this->registerConsoleMeteringInstrumentationConfiguration($container, $config['console']);
51✔
98

99
        $this->registerDoctrineTracingInstrumentationConfiguration($container, $config['doctrine']);
51✔
100
        $this->registerHttpClientTracingInstrumentationConfiguration($container, $config['http_client']);
51✔
101

102
        $this->registerHttpKernelTracingInstrumentationConfiguration($container, $config['http_kernel']);
51✔
103
        $this->registerHttpKernelMeteringInstrumentationConfiguration($container, $config['http_kernel']);
51✔
104

105
        $this->registerMailerTracingInstrumentationConfiguration($container, $config['mailer']);
51✔
106
        $this->registerMessengerTracingInstrumentationConfiguration($container, $config['messenger']);
51✔
107
        $this->registerTwigTracingInstrumentationConfiguration($container, $config['twig']);
51✔
108
    }
109

110
    /**
111
     * @param InstrumentationConfig $config
112
     */
113
    private function registerCacheTracingInstrumentationConfiguration(ContainerBuilder $container, array $config): void
114
    {
115
        $isConfigEnabled = $this->isConfigEnabled($container, $config['tracing']);
51✔
116

117
        if ($isConfigEnabled && !class_exists(CacheItem::class)) {
51✔
118
            throw new \LogicException('Cache instrumentation cannot be enabled because the symfony/cache package is not installed.');
×
119
        }
120

121
        if (!$isConfigEnabled) {
51✔
122
            $container->removeDefinition('open_telemetry.instrumentation.cache.trace.adapter');
45✔
123
            $container->removeDefinition('open_telemetry.instrumentation.cache.trace.tag_aware_adapter');
45✔
124
        }
125

126
        $this->setTracingInstrumentationParams($container, 'cache', $config, $isConfigEnabled);
51✔
127
    }
128

129
    /**
130
     * @param InstrumentationConfig $config
131
     */
132
    private function registerConsoleTracingInstrumentationConfiguration(ContainerBuilder $container, array $config): void
133
    {
134
        $isConfigEnabled = $this->isConfigEnabled($container, $config['tracing']);
51✔
135

136
        if ($isConfigEnabled && !class_exists(Command::class)) {
51✔
137
            throw new \LogicException('Console instrumentation cannot be enabled because the symfony/console package is not installed.');
×
138
        }
139

140
        if (!$isConfigEnabled) {
51✔
141
            $container->removeDefinition('open_telemetry.instrumentation.console.trace.event_subscriber');
45✔
142
        }
143

144
        $this->setTracingInstrumentationParams($container, 'console', $config, $isConfigEnabled);
51✔
145
    }
146

147
    /**
148
     * @param InstrumentationConfig $config
149
     */
150
    private function registerConsoleMeteringInstrumentationConfiguration(ContainerBuilder $container, array $config): void
151
    {
152
        $isConfigEnabled = $this->isConfigEnabled($container, $config['metering']);
51✔
153

154
        if ($isConfigEnabled && !class_exists(Command::class)) {
51✔
NEW
155
            throw new \LogicException('Console instrumentation cannot be enabled because the symfony/console package is not installed.');
×
156
        }
157

158
        if (!$isConfigEnabled) {
51✔
159
            $container->removeDefinition('open_telemetry.instrumentation.console.metric.event_subscriber');
45✔
160
        }
161
    }
162

163
    /**
164
     * @param InstrumentationConfig $config
165
     */
166
    private function registerDoctrineTracingInstrumentationConfiguration(ContainerBuilder $container, array $config): void
167
    {
168
        $isConfigEnabled = $this->isConfigEnabled($container, $config['tracing']);
51✔
169

170
        if ($isConfigEnabled && !class_exists(DoctrineBundle::class)) {
51✔
171
            throw new \LogicException('DBAL tracing support cannot be enabled because the doctrine/doctrine-bundle Composer package is not installed.');
×
172
        }
173

174
        if (!$isConfigEnabled) {
51✔
175
            $container->removeDefinition('open_telemetry.instrumentation.doctrine.trace.middleware');
48✔
176
        }
177

178
        $this->setTracingInstrumentationParams($container, 'doctrine', $config, $isConfigEnabled);
51✔
179
    }
180

181
    /**
182
     * @param InstrumentationConfig $config
183
     */
184
    private function registerHttpClientTracingInstrumentationConfiguration(ContainerBuilder $container, array $config): void
185
    {
186
        $isConfigEnabled = $this->isConfigEnabled($container, $config['tracing']);
51✔
187

188
        if ($isConfigEnabled && !class_exists(HttpClient::class)) {
51✔
189
            throw new \LogicException('Http client tracing support cannot be enabled because the symfony/http-client Composer package is not installed.');
×
190
        }
191

192
        if (!$isConfigEnabled) {
51✔
193
            $container->removeDefinition('open_telemetry.instrumentation.http_client.trace.client');
45✔
194
        }
195

196
        $this->setTracingInstrumentationParams($container, 'http_client', $config, $isConfigEnabled);
51✔
197
    }
198

199
    /**
200
     * @param InstrumentationConfig $config
201
     */
202
    private function registerHttpKernelTracingInstrumentationConfiguration(ContainerBuilder $container, array $config): void
203
    {
204
        $isConfigEnabled = $this->isConfigEnabled($container, $config['tracing']);
51✔
205

206
        if (!$isConfigEnabled) {
51✔
207
            $container->removeDefinition('open_telemetry.instrumentation.http_kernel.trace.event_subscriber');
45✔
208
            $container->removeDefinition('open_telemetry.instrumentation.http_kernel.trace.route_loader');
45✔
209
        }
210

211
        $this->setTracingInstrumentationParams($container, 'http_kernel', $config, $isConfigEnabled);
51✔
212
    }
213

214
    /**
215
     * @param InstrumentationConfig $config
216
     */
217
    private function registerHttpKernelMeteringInstrumentationConfiguration(ContainerBuilder $container, array $config): void
218
    {
219
        $isConfigEnabled = $this->isConfigEnabled($container, $config['metering']);
51✔
220

221
        if (!$isConfigEnabled) {
51✔
222
            $container->removeDefinition('open_telemetry.instrumentation.http_kernel.metric.event_subscriber');
45✔
223
        }
224
    }
225

226
    /**
227
     * @param InstrumentationConfig $config
228
     */
229
    private function registerMailerTracingInstrumentationConfiguration(ContainerBuilder $container, array $config): void
230
    {
231
        $isConfigEnabled = $this->isConfigEnabled($container, $config['tracing']);
51✔
232

233
        if ($isConfigEnabled && !interface_exists(MailerInterface::class)) {
51✔
234
            throw new \LogicException('Mailer instrumentation cannot be enabled because the symfony/mailer package is not installed.');
×
235
        }
236

237
        if (!$isConfigEnabled) {
51✔
238
            $container->removeDefinition('open_telemetry.instrumentation.mailer.trace.transports');
45✔
239
            $container->removeDefinition('open_telemetry.instrumentation.mailer.trace.default_transport');
45✔
240
            $container->removeDefinition('open_telemetry.instrumentation.mailer.trace.mailer');
45✔
241
        }
242

243
        $this->setTracingInstrumentationParams($container, 'mailer', $config, $isConfigEnabled);
51✔
244
    }
245

246
    /**
247
     * @param InstrumentationConfig $config
248
     */
249
    private function registerMessengerTracingInstrumentationConfiguration(ContainerBuilder $container, array $config): void
250
    {
251
        $isConfigEnabled = $this->isConfigEnabled($container, $config['tracing']);
51✔
252

253
        if ($isConfigEnabled && !class_exists(Envelope::class)) {
51✔
254
            throw new \LogicException('Messenger instrumentation cannot be enabled because the symfony/messenger package is not installed.');
×
255
        }
256

257
        if (!$isConfigEnabled) {
51✔
258
            $container->removeAlias('messenger.transport.open_telemetry_tracer.factory');
45✔
259
            $container->removeAlias('messenger.middleware.open_telemetry_tracer');
45✔
260
            $container->removeDefinition('open_telemetry.instrumentation.messenger.trace.transport');
45✔
261
            $container->removeDefinition('open_telemetry.instrumentation.messenger.trace.transport_factory');
45✔
262
            $container->removeDefinition('open_telemetry.instrumentation.messenger.trace.middleware');
45✔
263
        }
264

265
        $this->setTracingInstrumentationParams($container, 'messenger', $config, $isConfigEnabled);
51✔
266
    }
267

268
    /**
269
     * @param InstrumentationConfig $config
270
     */
271
    private function registerTwigTracingInstrumentationConfiguration(ContainerBuilder $container, array $config): void
272
    {
273
        $isConfigEnabled = $this->isConfigEnabled($container, $config['tracing']);
51✔
274

275
        if ($isConfigEnabled && !class_exists(TwigBundle::class)) {
51✔
276
            throw new \LogicException('Twig instrumentation cannot be enabled because the symfony/twig-bundle package is not installed.');
×
277
        }
278

279
        if (!$isConfigEnabled) {
51✔
280
            $container->removeDefinition('open_telemetry.instrumentation.twig.trace.extension');
45✔
281
        }
282

283
        $this->setTracingInstrumentationParams($container, 'twig', $config, $isConfigEnabled);
51✔
284
    }
285

286
    /**
287
     * @param InstrumentationConfig $config
288
     */
289
    private function setTracingInstrumentationParams(ContainerBuilder $container, string $name, array $config, bool $enabled): void
290
    {
291
        $container->setParameter(sprintf('open_telemetry.instrumentation.%s.tracing.enabled', $name), $enabled);
51✔
292
        if (isset($config['type'])) {
51✔
293
            $container->setParameter(
51✔
294
                sprintf('open_telemetry.instrumentation.%s.type', $name),
51✔
295
                InstrumentationTypeEnum::from($config['type']),
51✔
296
            );
51✔
297
        }
298

299
        if ('http_kernel' === $name) {
51✔
300
            if (isset($config['tracing']['exclude_paths'])
51✔
301
                && 0 < \count($config['tracing']['exclude_paths'])
51✔
302
            ) {
303
                $container->setParameter(
6✔
304
                    sprintf('open_telemetry.instrumentation.%s.tracing.exclude_paths', $name),
6✔
305
                    $config['tracing']['exclude_paths'],
6✔
306
                );
6✔
307
            }
308
        }
309

310
        if ('console' === $name) {
51✔
311
            if (isset($config['tracing']['exclude_commands'])
51✔
312
                && 0 < \count($config['tracing']['exclude_commands'])
51✔
313
            ) {
314
                $container->setParameter(
6✔
315
                    sprintf('open_telemetry.instrumentation.%s.tracing.exclude_commands', $name),
6✔
316
                    $config['tracing']['exclude_commands'],
6✔
317
                );
6✔
318
            }
319
        }
320

321
        $container->setParameter(
51✔
322
            sprintf('open_telemetry.instrumentation.%s.tracing.tracer', $name),
51✔
323
            $config['tracing']['tracer'] ?? 'default_tracer',
51✔
324
        );
51✔
325
    }
326
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc