Skip to content
This repository was archived by the owner on Oct 3, 2023. It is now read-only.

Commit f1a7eed

Browse files
authored
Simplify TraceSpan. (#6)
* Simplify TraceSpan. Kind is now optional and stored in a metadata array. Start and end times are stored as \DateTime objects. * span id should be an int * Add getters for span start and end time. Test date formats
1 parent 183478e commit f1a7eed

4 files changed

Lines changed: 73 additions & 75 deletions

File tree

src/Trace/TraceSpan.php

Lines changed: 51 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -18,82 +18,85 @@
1818
namespace OpenCensus\Trace;
1919

2020
/**
21-
* This plain PHP class represents a
22-
* [TraceSpan resource](https://cloud.google.com/trace/docs/reference/v1/rest/v1/projects.traces#TraceSpan)
23-
* A span represents a single timed event within a Trace. Spans can be nested
24-
* and form a trace tree. Often, a trace contains a root span that describes
25-
* the end-to-end latency of an operation and, optionally, one or more subspans
21+
* This plain PHP class represents a single timed event within a Trace. Spans can
22+
* be nested and form a trace tree. Often, a trace contains a root span that
23+
* describes the end-to-end latency of an operation and, optionally, one or more subspans
2624
* for its suboperations. Spans do not need to be contiguous. There may be
2725
* gaps between spans in a trace.
2826
*/
29-
class TraceSpan implements \JsonSerializable
27+
class TraceSpan
3028
{
31-
const SPAN_KIND_UNSPECIFIED = 'SPAN_KIND_UNSPECIFIED';
32-
const SPAN_KIND_RPC_SERVER = 'RPC_SERVER';
33-
const SPAN_KIND_RPC_CLIENT = 'RPC_CLIENT';
34-
3529
/**
36-
* @var array Associative array containing all the fields representing this TraceSpan.
30+
* @var array Associative array containing all the fields representing this Span.
3731
*/
3832
private $info = [];
3933

4034
/**
41-
* Instantiate a new TraceSpan instance.
35+
* Instantiate a new Span instance.
4236
*
4337
* @param array $options [optional] {
4438
* Configuration options.
4539
*
46-
* @type string $spanId The ID of the span. If not provided,
40+
* @type int $spanId The ID of the span. If not provided,
4741
* one will be generated automatically for you.
48-
* @type string $kind Distinguishes between spans generated
49-
* in a particular context. **Defaults to**
50-
* SPAN_KIND_UNSPECIFIED.
5142
* @type string $name The name of the span.
5243
* @type \DateTimeInterface|int|float|string $startTime Start time of the span in nanoseconds.
5344
* If provided as a string, it must be in "Zulu" format. If provided as an int or float, it is
5445
* expected to be a Unix timestamp.
5546
* @type \DateTimeInterface|int|float|string $endTime End time of the span in nanoseconds.
5647
* If provided as a string, it must be in "Zulu" format. If provided as an int or float, it is
5748
* expected to be a Unix timestamp.
58-
* @type string $parentSpanId ID of the parent span if any.
49+
* @type int $parentSpanId ID of the parent span if any.
5950
* @type array $labels Associative array of $label => $value
6051
* to attach to this span.
6152
* }
6253
*/
6354
public function __construct($options = [])
6455
{
6556
if (array_key_exists('startTime', $options)) {
66-
$this->setStart($options['startTime']);
57+
$this->setStartTime($options['startTime']);
58+
unset($options['startTime']);
6759
}
6860
if (array_key_exists('endTime', $options)) {
69-
$this->setEnd($options['endTime']);
61+
$this->setEndTime($options['endTime']);
62+
unset($options['endTime']);
7063
}
7164

7265
if (array_key_exists('labels', $options)) {
7366
$this->addLabels($options['labels']);
67+
unset($options['labels']);
7468
}
7569

7670
if (array_key_exists('spanId', $options)) {
7771
$this->info['spanId'] = $options['spanId'];
72+
unset($options['spanId']);
7873
} else {
7974
$this->info['spanId'] = $this->generateSpanId();
8075
}
8176

82-
if (array_key_exists('kind', $options)) {
83-
$this->info['kind'] = $options['kind'];
84-
} else {
85-
$this->info['kind'] = self::SPAN_KIND_UNSPECIFIED;
86-
}
87-
8877
if (array_key_exists('name', $options)) {
8978
$this->info['name'] = $options['name'];
79+
unset($options['name']);
9080
} else {
9181
$this->info['name'] = $this->generateSpanName();
9282
}
9383

9484
if (array_key_exists('parentSpanId', $options)) {
9585
$this->info['parentSpanId'] = $options['parentSpanId'];
86+
unset($options['parentSpanId']);
9687
}
88+
89+
$this->info['metadata'] = $options;
90+
}
91+
92+
/**
93+
* Retrieve the start time for this span.
94+
*
95+
* @return \DateTimeInterface
96+
*/
97+
public function startTime()
98+
{
99+
return $this->info['startTime'];
97100
}
98101

99102
/**
@@ -103,27 +106,37 @@ public function __construct($options = [])
103106
* **Defaults to** now. If provided as a string, it must be in "Zulu" format.
104107
* If provided as an int or float, it is expected to be a Unix timestamp.
105108
*/
106-
public function setStart($when = null)
109+
public function setStartTime($when = null)
107110
{
108111
$this->info['startTime'] = $this->formatDate($when);
109112
}
110113

114+
/**
115+
* Retrieve the end time for this span.
116+
*
117+
* @return \DateTimeInterface
118+
*/
119+
public function endTime()
120+
{
121+
return $this->info['endTime'];
122+
}
123+
111124
/**
112125
* Set the end time for this span.
113126
*
114127
* @param \DateTimeInterface|int|float|string $when [optional] The end time of this span.
115128
* **Defaults to** now. If provided as a string, it must be in "Zulu" format.
116129
* If provided as an int or float, it is expected to be a Unix timestamp.
117130
*/
118-
public function setEnd($when = null)
131+
public function setEndTime($when = null)
119132
{
120133
$this->info['endTime'] = $this->formatDate($when);
121134
}
122135

123136
/**
124137
* Retrieve the ID of this span.
125138
*
126-
* @return string
139+
* @return int
127140
*/
128141
public function spanId()
129142
{
@@ -133,7 +146,7 @@ public function spanId()
133146
/**
134147
* Retrieve the ID of this span's parent if it exists.
135148
*
136-
* @return string
149+
* @return int
137150
*/
138151
public function parentSpanId()
139152
{
@@ -162,16 +175,6 @@ public function info()
162175
return $this->info;
163176
}
164177

165-
/**
166-
* Returns the info array for serialization.
167-
*
168-
* @return array
169-
*/
170-
public function jsonSerialize()
171-
{
172-
return $this->info;
173-
}
174-
175178
/**
176179
* Attach labels to this span.
177180
*
@@ -201,37 +204,38 @@ public function addLabel($label, $value)
201204
/**
202205
* Returns a "Zulu" formatted string representing the provided \DateTime.
203206
*
204-
* @param \DateTimeInterface|int|float|string $when [optional] The end time of this span.
207+
* @param \DateTimeInterface|int|float $when [optional] The end time of this span.
205208
* **Defaults to** now. If provided as a string, it must be in "Zulu" format.
206209
* If provided as an int or float, it is expected to be a Unix timestamp.
207-
* @return string
210+
* @return \DateTimeInterface
208211
*/
209212
private function formatDate($when = null)
210213
{
211-
if (is_string($when)) {
212-
return $when;
213-
} elseif (!$when) {
214+
if (!$when) {
215+
// now
214216
list($usec, $sec) = explode(' ', microtime());
215217
$micro = sprintf("%06d", $usec * 1000000);
216218
$when = new \DateTime(date('Y-m-d H:i:s.' . $micro));
217219
} elseif (is_numeric($when)) {
218220
// Expect that this is a timestamp
219221
$micro = sprintf("%06d", ($when - floor($when)) * 1000000);
220222
$when = new \DateTime(date('Y-m-d H:i:s.'. $micro, (int) $when));
223+
} elseif (!$when instanceof \DateTimeInterface) {
224+
throw new \InvalidArgumentException('Invalid date format. Must be a \DateTimeInterface or numeric.');
221225
}
222226
$when->setTimezone(new \DateTimeZone('UTC'));
223-
return $when->format('Y-m-d\TH:i:s.u000\Z');
227+
return $when;
224228
}
225229

226230
/**
227231
* Generate a random ID for this span. Must be unique per trace,
228232
* but does not need to be globally unique.
229233
*
230-
* @return string
234+
* @return int
231235
*/
232236
private function generateSpanId()
233237
{
234-
return '' . mt_rand();
238+
return mt_rand();
235239
}
236240

237241
/**

src/Trace/Tracer/ContextTracer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public function endSpan()
101101
$span = array_shift($this->stack);
102102
$this->context->setSpanId(empty($this->stack) ? null : $this->stack[0]->spanId());
103103
if ($span) {
104-
$span->setEnd();
104+
$span->setEndTime();
105105
return true;
106106
}
107107
return false;

tests/unit/Trace/TraceSpanTest.php

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ public function testGeneratesDefaultSpanId()
3131
$traceSpan = new TraceSpan();
3232
$info = $traceSpan->info();
3333
$this->assertArrayHasKey('spanId', $info);
34-
$this->assertRegExp('/^\d+$/', $info['spanId']);
3534
$this->assertEquals($info['spanId'], $traceSpan->spanId());
3635
}
3736

@@ -94,35 +93,19 @@ public function testReadsName()
9493
public function testStartFormat()
9594
{
9695
$traceSpan = new TraceSpan();
97-
$traceSpan->setStart();
96+
$traceSpan->setStartTime();
9897
$info = $traceSpan->info();
9998
$this->assertArrayHasKey('startTime', $info);
100-
$this->assertRegExp(self::EXPECTED_TIMESTAMP_FORMAT, $info['startTime']);
99+
$this->assertInstanceOf(\DateTimeInterface::class, $info['startTime']);
101100
}
102101

103102
public function testFinishFormat()
104103
{
105104
$traceSpan = new TraceSpan();
106-
$traceSpan->setEnd();
105+
$traceSpan->setEndTime();
107106
$info = $traceSpan->info();
108107
$this->assertArrayHasKey('endTime', $info);
109-
$this->assertRegExp(self::EXPECTED_TIMESTAMP_FORMAT, $info['endTime']);
110-
}
111-
112-
public function testGeneratesDefaultKind()
113-
{
114-
$traceSpan = new TraceSpan();
115-
$info = $traceSpan->info();
116-
$this->assertArrayHasKey('kind', $info);
117-
$this->assertEquals(TraceSpan::SPAN_KIND_UNSPECIFIED, $info['kind']);
118-
}
119-
120-
public function testReadsKind()
121-
{
122-
$traceSpan = new TraceSpan(['kind' => TraceSpan::SPAN_KIND_RPC_CLIENT]);
123-
$info = $traceSpan->info();
124-
$this->assertArrayHasKey('kind', $info);
125-
$this->assertEquals(TraceSpan::SPAN_KIND_RPC_CLIENT, $info['kind']);
108+
$this->assertInstanceOf(\DateTimeInterface::class, $info['endTime']);
126109
}
127110

128111
public function testIgnoresUnknownFields()
@@ -138,18 +121,16 @@ public function testIgnoresUnknownFields()
138121
public function testCanFormatTimestamps($field, $timestamp, $expected)
139122
{
140123
$traceSpan = new TraceSpan([$field => $timestamp]);
141-
$this->assertEquals($expected, $traceSpan->info()[$field]);
124+
$this->assertEquals($expected, $traceSpan->info()[$field]->format('Y-m-d\TH:i:s.u000\Z'));
142125
}
143126

144127
public function timestampFields()
145128
{
146129
return [
147130
['startTime', 1490737410, '2017-03-28T21:43:30.000000000Z'],
148131
['startTime', 1490737450.4843, '2017-03-28T21:44:10.484299000Z'],
149-
['startTime', '2017-03-28T21:44:10.484299000Z', '2017-03-28T21:44:10.484299000Z'],
150132
['endTime', 1490737410, '2017-03-28T21:43:30.000000000Z'],
151133
['endTime', 1490737450.4843, '2017-03-28T21:44:10.484299000Z'],
152-
['endTime', '2017-03-28T21:44:10.484299000Z', '2017-03-28T21:44:10.484299000Z'],
153134
];
154135
}
155136
}

tests/unit/Trace/TraceTest.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
*/
2626
class TraceTest extends \PHPUnit_Framework_TestCase
2727
{
28-
public function testLoadFromArray()
28+
/**
29+
* @dataProvider dateFormats
30+
*/
31+
public function testLoadFromArray($date)
2932
{
3033
$trace = new Trace(
3134
'1234abcd',
@@ -34,15 +37,17 @@ public function testLoadFromArray()
3437
'spanId' => '12345',
3538
'kind' => 'SPAN_KIND_UNSPECIFIED',
3639
'name' => 'spanname',
37-
'startTime' => '2017-03-28T21:44:10.484299000Z',
38-
'endTime' => '2017-03-28T21:44:11.123456000Z'
40+
'startTime' => $date,
41+
'endTime' => $date
3942
]
4043
]
4144
);
4245
$this->assertEquals('1234abcd', $trace->traceId());
4346
$this->assertEquals(1, count($trace->spans()));
4447
foreach($trace->spans() as $span) {
4548
$this->assertInstanceOf(TraceSpan::class, $span);
49+
$this->assertInstanceOf(\DateTimeInterface::class, $span->startTime());
50+
$this->assertInstanceOf(\DateTimeInterface::class, $span->endTime());
4651
}
4752
}
4853

@@ -65,4 +70,12 @@ public function testSpecifyingSpansSkipsTraceGetCall()
6570
$trace = new Trace('1', [['name' => 'main']]);
6671
$trace->info();
6772
}
73+
74+
public function dateFormats()
75+
{
76+
return [
77+
[1490737450.4843],
78+
[new \DateTime()]
79+
];
80+
}
6881
}

0 commit comments

Comments
 (0)