Skip to content

Commit b44df6d

Browse files
authored
Refactor Baggage (#416)
* Scaffold out initial `Baggage` implementation Do some reorganizing of `Context` * Implement `BaggageBuilder` * Add some additional docs/tests
1 parent 1cfd72a commit b44df6d

14 files changed

Lines changed: 540 additions & 277 deletions

Context/Context.php

Lines changed: 105 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,29 @@
77
/**
88
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/context/context.md#overview
99
*/
10-
class Context
10+
final class Context
1111
{
12-
/**
13-
* @var ContextKey|null
14-
*/
15-
protected $key;
12+
/** @var self|null */
13+
private static $current_context;
14+
15+
/** @var self|null */
16+
private static $root;
1617

1718
/**
18-
* @var mixed|null
19+
* This will set the given Context to be the "current" one. We return a token which can be passed to `detach()` to
20+
* reset the Current Context back to the previous one.
21+
*
22+
* @return callable():Context - token for resetting the $current_context back
1923
*/
20-
protected $value;
21-
22-
/** @var self|null */
23-
protected $parent;
24+
public static function attach(Context $ctx): callable
25+
{
26+
$former_ctx = self::getCurrent();
27+
self::$current_context = $ctx;
2428

25-
protected static $current_context = null;
29+
return static function () use ($former_ctx) {
30+
return $former_ctx;
31+
};
32+
}
2633

2734
/**
2835
* @param non-empty-string $key
@@ -34,6 +41,92 @@ public static function createKey(string $key): ContextKey
3441
return new ContextKey($key);
3542
}
3643

44+
/**
45+
* Given a token, the current context will be set back to the one prior to the token being generated.
46+
* @param callable():Context $token
47+
*/
48+
public static function detach(callable $token): Context
49+
{
50+
return self::$current_context = $token();
51+
}
52+
53+
public static function getCurrent(): Context
54+
{
55+
return self::$current_context ?? (self::$current_context = self::getRoot());
56+
}
57+
58+
public static function getRoot(): self
59+
{
60+
if (null === self::$root) {
61+
self::$root = new self();
62+
}
63+
64+
return self::$root;
65+
}
66+
67+
/**
68+
* Static version of get()
69+
* This is primarily useful when the caller doesn't already have a reference to the Context that they want to mutate.
70+
* This will operate on the "current" global context in that scenario.
71+
*
72+
* There are two ways to call this function:
73+
* 1) With a $ctx value:
74+
* Context::getValue($key, $ctx) is functionally equivalent to $ctx->get($key)
75+
* 2) Without a $ctx value:
76+
* This will fetch the "current" Context if one exists or create one if not, then attempt to get the value from it.
77+
*
78+
* @param ContextKey $key
79+
* @param Context|null $ctx
80+
*
81+
* @return mixed
82+
*/
83+
public static function getValue(ContextKey $key, $ctx=null)
84+
{
85+
$ctx = $ctx ?? static::getCurrent();
86+
87+
return $ctx->get($key);
88+
}
89+
90+
/**
91+
* This is a static version of set().
92+
* This is primarily useful when the caller doesn't already have a reference to a Context that they want to mutate.
93+
*
94+
* There are two ways to call this function.
95+
* 1) With a $parent parameter:
96+
* Context::setValue($key, $value, $ctx) is functionally equivalent to $ctx->set($key, $value)
97+
* 2) Without a $parent parameter:
98+
* In this scenario, setValue() will use the `$current_context` reference as supplied by `getCurrent()`
99+
* `getCurrent()` will always return a valid Context. If one does not exist at the global scope,
100+
* an "empty" context will be created.
101+
*
102+
* @param ContextKey $key
103+
* @param mixed $value
104+
* @param Context|null $parent
105+
*
106+
* @return Context a new Context containing the k/v
107+
*/
108+
public static function withValue(ContextKey $key, $value, $parent=null)
109+
{
110+
if (null === $parent) {
111+
return self::$current_context = new self($key, $value, self::getCurrent());
112+
}
113+
114+
return new self($key, $value, $parent);
115+
}
116+
117+
/**
118+
* @var ContextKey|null
119+
*/
120+
protected $key;
121+
122+
/**
123+
* @var mixed|null
124+
*/
125+
protected $value;
126+
127+
/** @var self|null */
128+
protected $parent;
129+
37130
/**
38131
* This is a general purpose read-only key-value store. Read-only in the sense that adding a new value does not
39132
* mutate the existing context, but returns a new Context which has the new value added.
@@ -69,7 +162,7 @@ final public function __construct(?ContextKey $key=null, $value=null, $parent=nu
69162
*/
70163
public function with(ContextKey $key, $value)
71164
{
72-
return new static($key, $value, $this);
165+
return new self($key, $value, $this);
73166
}
74167

75168
/**
@@ -90,33 +183,6 @@ public function activate(): Scope
90183
return new Scope(self::attach($this));
91184
}
92185

93-
/**
94-
* This is a static version of set().
95-
* This is primarily useful when the caller doesn't already have a reference to a Context that they want to mutate.
96-
*
97-
* There are two ways to call this function.
98-
* 1) With a $parent parameter:
99-
* Context::setValue($key, $value, $ctx) is functionally equivalent to $ctx->set($key, $value)
100-
* 2) Without a $parent parameter:
101-
* In this scenario, setValue() will use the `$current_context` reference as supplied by `getCurrent()`
102-
* `getCurrent()` will always return a valid Context. If one does not exist at the global scope,
103-
* an "empty" context will be created.
104-
*
105-
* @param ContextKey $key
106-
* @param mixed $value
107-
* @param Context|null $parent
108-
*
109-
* @return Context a new Context containing the k/v
110-
*/
111-
public static function withValue(ContextKey $key, $value, $parent=null)
112-
{
113-
if (null === $parent) {
114-
return static::$current_context = new static($key, $value, static::getCurrent());
115-
}
116-
117-
return new static($key, $value, $parent);
118-
}
119-
120186
/**
121187
* Fetch a value from the Context given a key value.
122188
*
@@ -134,66 +200,4 @@ public function get(ContextKey $key)
134200

135201
return $this->parent->get($key);
136202
}
137-
138-
/**
139-
* Static version of get()
140-
* This is primarily useful when the caller doesn't already have a reference to the Context that they want to mutate.
141-
* This will operate on the "current" global context in that scenario.
142-
*
143-
* There are two ways to call this function:
144-
* 1) With a $ctx value:
145-
* Context::getValue($key, $ctx) is functionally equivalent to $ctx->get($key)
146-
* 2) Without a $ctx value:
147-
* This will fetch the "current" Context if one exists or create one if not, then attempt to get the value from it.
148-
*
149-
* @param ContextKey $key
150-
* @param Context|null $ctx
151-
*
152-
* @return mixed
153-
*/
154-
public static function getValue(ContextKey $key, $ctx=null)
155-
{
156-
$ctx = $ctx ?? static::getCurrent();
157-
158-
return $ctx->get($key);
159-
}
160-
161-
public static function getCurrent(): Context
162-
{
163-
if (null === static::$current_context) {
164-
static::$current_context = new static();
165-
}
166-
167-
return static::$current_context;
168-
}
169-
170-
/**
171-
* This will set the given Context to be the "current" one. We return a token which can be passed to `detach()` to
172-
* reset the Current Context back to the previous one.
173-
*
174-
* @param Context $ctx
175-
*
176-
* @return callable token for resetting the $current_context back
177-
*/
178-
public static function attach($ctx): callable
179-
{
180-
$former_ctx = static::$current_context;
181-
static::$current_context = $ctx;
182-
183-
return function () use ($former_ctx) {
184-
return $former_ctx;
185-
};
186-
}
187-
188-
/**
189-
* Given a token, the current context will be set back to the one prior to the token being generated.
190-
*
191-
* @param callable $token
192-
*
193-
* @return Context
194-
*/
195-
public static function detach(callable $token)
196-
{
197-
return static::$current_context = call_user_func($token);
198-
}
199203
}

Context/ImplicitContextKeyed.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
* Allows storing themselves without exposing a {@see ContextKey}.
1010
*
1111
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/trace/api.md#context-interaction
12+
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/baggage/api.md#context-interaction
13+
*
1214
* @todo: Implement this on the API side
1315
*/
1416
interface ImplicitContextKeyed

api/Baggage.php

Lines changed: 0 additions & 24 deletions
This file was deleted.

api/Baggage/Baggage.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenTelemetry\Baggage;
6+
7+
use OpenTelemetry\Baggage as API;
8+
use OpenTelemetry\Context\Context;
9+
use OpenTelemetry\Context\ImplicitContextKeyed;
10+
11+
/**
12+
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/baggage/api.md#operations
13+
*/
14+
interface Baggage extends ImplicitContextKeyed
15+
{
16+
/**
17+
* Returns the {@see API\Baggage} from the provided *$context*,
18+
* falling back on {@see API\Baggage::getEmpty()} if there is no baggage in the provided context.
19+
*
20+
* @todo Implement this in the API layer
21+
*/
22+
public static function fromContext(Context $context): API\Baggage;
23+
24+
/**
25+
* Returns a new empty {@see API\BaggageBuilder}.
26+
*/
27+
public static function getBuilder(): API\BaggageBuilder;
28+
29+
/**
30+
* Returns the current {@see Baggage} from the current {@see Context},
31+
* falling back on {@see API\Baggage::getEmpty()} if there is no baggage in the current context.
32+
*
33+
* @todo Implement this in the API layer
34+
*/
35+
public static function getCurrent(): API\Baggage;
36+
37+
/**
38+
* Returns a new {@see API\Baggage} with no entries.
39+
*/
40+
public static function getEmpty(): API\Baggage;
41+
42+
/**
43+
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/baggage/api.md#get-value
44+
*/
45+
public function getEntry(string $key): ?API\Entry;
46+
47+
/**
48+
* Returns the value from the {@see API\Entry} with the provided *key*.
49+
* @see getEntry
50+
*
51+
* @return mixed
52+
*/
53+
public function getValue(string $key);
54+
55+
/**
56+
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/baggage/api.md#get-all-values
57+
*/
58+
public function getAll(): iterable;
59+
60+
/**
61+
* Returns a new {@see API\BaggageBuilder} pre-initialized with the contents of `$this`.
62+
*/
63+
public function toBuilder(): API\BaggageBuilder;
64+
}

api/Baggage/BaggageBuilder.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenTelemetry\Baggage;
6+
7+
use OpenTelemetry\Baggage as API;
8+
9+
interface BaggageBuilder
10+
{
11+
/**
12+
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/baggage/api.md#set-value
13+
*/
14+
public function set(string $key, $value, API\Metadata $metadata = null): API\BaggageBuilder;
15+
16+
/**
17+
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.6.1/specification/baggage/api.md#remove-value
18+
*/
19+
public function remove(string $key): API\BaggageBuilder;
20+
21+
public function build(): API\Baggage;
22+
}

0 commit comments

Comments
 (0)