Passed
Push — master ( 7836cc...537efa )
by Zoilo
03:57
created

ElasticApmTracer::startSpan()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 33
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 2

Importance

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