Passed
Push — master ( d0c075...584a68 )
by Zoilo
02:35 queued 37s
created

ElasticApmTracer::active()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
namespace ZoiloMora\ElasticAPM;
4
5
use ZoiloMora\ElasticAPM\Configuration\CoreConfiguration;
6
use ZoiloMora\ElasticAPM\Events\Common\Context;
7
use ZoiloMora\ElasticAPM\Events\Error\Error;
8
use ZoiloMora\ElasticAPM\Events\Metadata\Metadata;
9
use ZoiloMora\ElasticAPM\Events\Span\Span;
10
use ZoiloMora\ElasticAPM\Events\TraceableEvent;
11
use ZoiloMora\ElasticAPM\Events\Transaction\Transaction;
12
use ZoiloMora\ElasticAPM\Helper\Stacktrace;
13
use ZoiloMora\ElasticAPM\Pool\ErrorPool;
14
use ZoiloMora\ElasticAPM\Pool\PoolFactory;
15
use ZoiloMora\ElasticAPM\Pool\SpanPool;
16
use ZoiloMora\ElasticAPM\Pool\TransactionPool;
17
use ZoiloMora\ElasticAPM\Processor\Handler;
18
use ZoiloMora\ElasticAPM\Reporter\Reporter;
19
20
final class ElasticApmTracer
21
{
22
    /**
23
     * @var CoreConfiguration
24
     */
25
    private $coreConfiguration;
26
27
    /**
28
     * @var Metadata
29
     */
30
    private $metadata;
31
32
    /**
33
     * @var Context
34
     */
35
    private $context;
36
37
    /**
38
     * @var Handler
39
     */
40
    private $handler;
41
42
    /**
43
     * @var Reporter
44
     */
45
    private $reporter;
46
47
    /**
48
     * @var TransactionPool
49
     */
50
    private $transactionPool;
51
52
    /**
53
     * @var SpanPool
54
     */
55
    private $spanPool;
56
57
    /**
58
     * @var ErrorPool
59
     */
60
    private $errorPool;
61
62 11
    public function __construct(
63
        CoreConfiguration $coreConfiguration,
64
        Reporter $reporter,
65
        PoolFactory $poolFactory
66
    ) {
67 11
        $this->coreConfiguration = $coreConfiguration;
68 11
        $this->reporter = $reporter;
69
70 11
        $this->metadata = Metadata::create($this->coreConfiguration);
71 11
        $this->context = Context::discover();
72 11
        $this->handler = Handler::create($this->coreConfiguration);
73
74 11
        $this->transactionPool = $poolFactory->createTransactionPool();
75 11
        $this->spanPool = $poolFactory->createSpanPool();
76 11
        $this->errorPool = $poolFactory->createErrorPool();
77 11
    }
78
79
    /**
80
     * @return bool
81
     */
82 3
    public function active()
83
    {
84 3
        return $this->coreConfiguration->active();
85
    }
86
87
    /**
88
     * @param string $name
89
     * @param string $type
90
     * @param Context $context
91
     *
92
     * @return Transaction
93
     *
94
     * @throws \Exception
95
     */
96 7
    public function startTransaction($name, $type, $context = null)
97
    {
98 6
        if (null === $context) {
99 6
            $context = $this->context;
100 6
        }
101
102 6
        $lastEvent = $this->getLastUnfinishedEvent();
103
104 6
        $transaction = new Transaction(
105 6
            $name,
106 6
            $type,
107 6
            $context,
108 6
            null !== $lastEvent ? $lastEvent->traceId() : null,
109 6
            null !== $lastEvent ? $lastEvent->id() : null
110 6
        );
111
112 7
        $this->transactionPool->put($transaction);
113
114 7
        return $transaction;
115
    }
116
117
    /**
118
     * @param string $name
119
     * @param string $type
120
     * @param string|null $subtype
121
     * @param string|null $action
122
     * @param Events\Span\Context|null $context
123
     * @param int $stacktraceSkip
124
     *
125
     * @return Span
126
     *
127
     * @throws \Exception
128
     */
129 4
    public function startSpan(
130
        $name,
131
        $type,
132
        $subtype = null,
133
        $action = null,
134
        Events\Span\Context $context = null,
135
        $stacktraceSkip = 1
136
    ) {
137 4
        $stacktrace = Stacktrace::getDebugBacktrace(
138 4
            $this->coreConfiguration->stacktraceLimit(),
139
            $stacktraceSkip
140 4
        );
141
142 4
        $lastTransaction = $this->transactionPool->findLastUnfinished();
143 4
        if (null === $lastTransaction) {
144 1
            throw new \Exception('To create a span, there must be a transaction started.');
145
        }
146
147 3
        $lastEvent = $this->getLastUnfinishedEvent();
148
149 3
        $span = new Span(
150 3
            $name,
151 3
            $type,
152 3
            $lastEvent->traceId(),
153 3
            $lastEvent->id(),
154 3
            $subtype,
155 3
            $lastTransaction->id(),
156 3
            $action,
157 3
            $context,
158
            $stacktrace
159 3
        );
160
161 3
        $this->spanPool->put($span);
162
163 3
        return $span;
164
    }
165
166
    /**
167
     * @param mixed $exception
168
     * @param Context|null $context
169
     *
170
     * @return void
171
     *
172
     * @throws \Exception
173
     */
174 2
    public function captureException($exception, Context $context = null)
175
    {
176 2
        $lastTransaction = $this->transactionPool->findLastUnfinished();
177 2
        if (null === $lastTransaction) {
178 1
            throw new \Exception('To capture exception, there must be a transaction started.');
179
        }
180
181 1
        $lastEvent = $this->getLastUnfinishedEvent();
182
183 1
        $error = new Error(
184 1
            $lastEvent->traceId(),
185 1
            $lastEvent->id(),
186 1
            $exception,
187 1
            $context,
188 1
            $lastTransaction->id()
189 1
        );
190
191 1
        $this->errorPool->put($error);
192 1
    }
193
194
    /**
195
     * @return void
196
     */
197 3
    public function flush()
198
    {
199 3
        if (false === $this->active()) {
200 1
            return;
201
        }
202
203 2
        $events = $this->getEventsToSend();
204
205 2
        if (0 === count($events)) {
206 1
            return;
207
        }
208
209 1
        $events = array_merge(
210
            [
211 1
                $this->metadata,
212 1
            ],
213
            $events
214 1
        );
215
216 1
        $events = $this->handler->execute($events);
217
218 1
        $this->reporter->report($events);
219 1
    }
220
221
    /**
222
     * @return array
223
     */
224 2
    private function getEventsToSend()
225
    {
226 2
        $transactions = $this->transactionPool->findFinishedAndDelete();
227
228 2
        $events = [];
229 2
        foreach ($transactions as $transaction) {
230 1
            $events = array_merge(
231 1
                $events,
232 1
                $this->spanPool->findFinishedAndDelete($transaction),
233 1
                $this->errorPool->findAndDelete($transaction)
234 1
            );
235 2
        }
236
237 2
        return array_merge(
238 2
            $transactions,
239
            $events
240 2
        );
241
    }
242
243
    /**
244
     * @return TraceableEvent|null
245
     */
246 6
    private function getLastUnfinishedEvent()
247
    {
248 6
        $lastTransaction = $this->transactionPool->findLastUnfinished();
249 6
        if (null === $lastTransaction) {
250 6
            return null;
251
        }
252
253 4
        $lastSpan = $this->spanPool->findLastUnfinished();
254 4
        if (null === $lastSpan) {
255 4
            return $lastTransaction;
256
        }
257
258 1
        return $lastTransaction->timestamp() > $lastSpan->timestamp()
259 1
            ? $lastTransaction
260 1
            : $lastSpan;
261
    }
262
}
263