DistributedTracing::fakeDistributedTracing()   A
last analyzed

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 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
namespace ZoiloMora\ElasticAPM\Helper;
4
5
final class DistributedTracing
6
{
7
    /**
8
     * Supporting Elastic's Traceparent Header until W3C goes GA
9
     *
10
     * @link https://www.w3.org/TR/trace-context/#header-name
11
     */
12
    const HEADER_NAME = 'ELASTIC-APM-TRACEPARENT';
13
14
    /**
15
     * @link https://www.w3.org/TR/trace-context/#version
16
     */
17
    const VERSION = '00';
18
19
    /**
20
     * @var DistributedTracing
21
     */
22
    private static $fakeDistributedTracing;
23
24
    /**
25
     * @var string
26
     */
27
    private $traceId;
28
29
    /**
30
     * @var string
31
     */
32
    private $parentId;
33
34
    /**
35
     * @var string
36
     */
37
    private $traceFlags;
38
39
    /**
40
     * @param DistributedTracing|null $fakeDistributedTracing
41
     *
42
     * @return void
43
     */
44 11
    public static function fakeDistributedTracing(DistributedTracing $fakeDistributedTracing = null)
45
    {
46 11
        self::$fakeDistributedTracing = $fakeDistributedTracing;
47 11
    }
48
49
    /**
50
     * @param string $traceId
51
     * @param string $parentId
52
     * @param string $traceFlags
53
     */
54 4
    public function __construct($traceId, $parentId, $traceFlags = '00')
55
    {
56 4
        $this->traceId = $traceId;
57 4
        $this->parentId = $parentId;
58 4
        $this->traceFlags = $traceFlags;
59 4
    }
60
61
    /**
62
     * @return string
63
     */
64 1
    public function traceId()
65
    {
66 1
        return $this->traceId;
67
    }
68
69
    /**
70
     * @return string
71
     */
72 1
    public function parentId()
73
    {
74 1
        return $this->parentId;
75
    }
76
77
    /**
78
     * @return string
79
     */
80 1
    public function traceFlags()
81
    {
82 1
        return $this->traceFlags;
83
    }
84
85
    /**
86
     * @return DistributedTracing|null
87
     *
88
     * @throws \Exception
89
     */
90 30
    public static function discoverDistributedTracing()
91
    {
92 30
        if (null !== self::$fakeDistributedTracing) {
93 2
            return self::$fakeDistributedTracing;
94
        }
95
96 28
        $traceHeader = self::traceHeader();
97 28
        if (null === $traceHeader) {
98 26
            return null;
99
        }
100
101 2
        return self::createFromHeader($traceHeader);
102
    }
103
104
    /**
105
     * @return string|null
106
     */
107 28
    private static function traceHeader()
108
    {
109 28
        $key = sprintf(
110 28
            'HTTP_%s',
111 28
            str_replace(
112 28
                '-',
113 28
                '_',
114
                self::HEADER_NAME
115 28
            )
116 28
        );
117
118 28
        if (false === array_key_exists($key, $_SERVER)) {
119 26
            return null;
120
        }
121
122 2
        return (string) $_SERVER[$key];
123
    }
124
125
    /**
126
     * Check if the Header Value is valid
127
     *
128
     * @link https://www.w3.org/TR/trace-context/#version-format
129
     *
130
     * @param string $header
131
     *
132
     * @return bool
133
     */
134 2
    private static function isValidHeader($header)
135
    {
136 2
        return 1 === preg_match(
137 2
            '/^' . self::VERSION . '-[\da-f]{32}-[\da-f]{16}-[\da-f]{2}$/',
138
            $header
139 2
        );
140
    }
141
142
    /**
143
     * @param string $header
144
     *
145
     * @return DistributedTracing
146
     *
147
     * @throws \Exception
148
     */
149 2
    private static function createFromHeader($header)
150
    {
151 2
        if (false === self::isValidHeader($header)) {
152 1
            throw new \Exception('Invalid distributed trace header.');
153
        }
154
155 1
        $parsed = explode('-', $header);
156
157 1
        return new self($parsed[1], $parsed[2], $parsed[3]);
158
    }
159
160
    /**
161
     * Get Distributed Tracing Id
162
     *
163
     * @return string
164
     */
165 3
    public function __toString()
166
    {
167 3
        return sprintf(
168 3
            '%s-%s-%s-%s',
169 3
            self::VERSION,
170 3
            $this->traceId,
171 3
            $this->parentId,
172 3
            $this->traceFlags
173 3
        );
174
    }
175
}
176