Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
IncidentReporterService
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 6
380
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 report
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 reportManual
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 dispatch
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 tryDeliver
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
72
 isEnabled
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace App\Modules\SupportModule\Services;
4
5use Throwable;
6
7class IncidentReporterService
8{
9    protected GlitchTipService $glitchTip;
10    protected SigNozService $signoz;
11    protected OpenObservableService $observable;
12    protected ContextBuilderService $contextBuilder;
13    protected IncidentQueueService $queue;
14
15    public function __construct()
16    {
17        $this->glitchTip      = service('glitchtip');
18        $this->signoz         = service('signoz');
19        $this->observable     = service('openObservable');
20        $this->contextBuilder = service('contextBuilder');
21        $this->queue          = service('incidentQueue');
22    }
23
24    /**
25     * ENTRYPOINT principal (exception runtime)
26     */
27    public function report(Throwable $e, array $context = []): void
28    {
29        if (! $this->isEnabled()) {
30            return;
31        }
32
33        try {
34            $payload = $this->contextBuilder->buildFromException($e, $context);
35
36            $this->dispatch($payload, $e);
37
38        } catch (Throwable $internal) {
39            log_message('critical', '[IncidentReporter][BUILD_FAILED] ' . $internal->getMessage());
40        }
41    }
42
43    /**
44     * Incident manuel utilisateur
45     */
46    public function reportManual(array $payload): void
47    {
48        if (! $this->isEnabled()) {
49            return;
50        }
51
52        try {
53            $payload = $this->contextBuilder->buildFromManual($payload);
54
55            $this->dispatch($payload, null);
56
57        } catch (Throwable $internal) {
58            log_message('error', '[IncidentReporter][MANUAL_FAILED] ' . $internal->getMessage());
59        }
60    }
61
62    /**
63     * Orchestration centrale
64     */
65    protected function dispatch(array $payload, ?Throwable $e): void
66    {
67        $delivered = $this->tryDeliver($payload, $e);
68
69        if (! $delivered) {
70            $this->queue->push($payload);
71        }
72    }
73
74    /**
75     * Livraison multi-canal
76     */
77    protected function tryDeliver(array $payload, ?Throwable $e): bool
78    {
79        $success = true;
80
81        /**
82         * 1. GlitchTip (erreurs applicatives)
83         */
84        try {
85            if ($e) {
86                $this->glitchTip->captureException($e);
87            } else {
88                $this->glitchTip->captureMessage(
89                    $payload['message'] ?? 'Incident',
90                    $payload['severity'] ?? 'info'
91                );
92            }
93        } catch (Throwable $ex) {
94            log_message('error', '[GlitchTip] ' . $ex->getMessage());
95            $success = false;
96        }
97
98        /**
99         * 2. SigNoz (traces techniques)
100         */
101        try {
102            $tracePayload = $payload;
103
104            if ($e) {
105                $tracePayload['error'] = $e->getMessage();
106            }
107
108            $this->signoz->sendTrace([
109                'name'    => $tracePayload['type'] ?? 'incident',
110                'status'  => $e ? 'error' : 'info',
111                'context' => $tracePayload,
112            ]);
113
114        } catch (Throwable $ex) {
115            log_message('error', '[SigNoz] ' . $ex->getMessage());
116            $success = false;
117        }
118
119        /**
120         * 3. OpenObservable (orchestration interne)
121         */
122        try {
123            if ($e) {
124                $payload['error'] = $e->getMessage();
125            }
126
127            $this->observable->traceIncident($payload);
128
129        } catch (Throwable $ex) {
130            log_message('error', '[OpenObservable] ' . $ex->getMessage());
131            $success = false;
132        }
133
134        return $success;
135    }
136
137    /**
138     * Activation du service
139     */
140    protected function isEnabled(): bool
141    {
142        try {
143            $model = model('App\Modules\SupportModule\Models\DiagnosticSettingModel');
144
145            $setting = $model->first();
146
147            return (bool) ($setting['enabled'] ?? false);
148
149        } catch (Throwable $e) {
150            log_message('error', '[IncidentReporter][ENABLED_CHECK] ' . $e->getMessage());
151            return false;
152        }
153    }
154}