3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
20 namespace MediaWiki\Http
;
22 use Wikimedia\Http\TelemetryHeadersInterface
;
25 * Service for handling telemetry data
29 class Telemetry
implements TelemetryHeadersInterface
{
34 private static ?Telemetry
$instance = null;
38 * @var string|null Request id
40 private ?
string $reqId = null;
43 * Server and execution environment information.
45 * @see https://www.php.net/manual/en/reserved.variables.server.php
48 private array $server;
50 private ?
bool $allowExternalReqID;
53 * @param array $server Server and execution environment information, most likely the $_SERVER variable
55 public function __construct( array $server, ?
bool $allowExternalReqID = null ) {
56 $this->server
= $server;
57 $this->allowExternalReqID
= $allowExternalReqID;
60 public static function getInstance(): Telemetry
{
61 if ( !self
::$instance ) {
62 global $wgAllowExternalReqID;
63 self
::$instance = new self( $_SERVER, $wgAllowExternalReqID );
66 return self
::$instance;
70 * Get the current request ID.
72 * This is usually based on the `X-Request-Id` header, or the `UNIQUE_ID`
73 * environment variable, falling back to (process cached) randomly-generated string.
77 public function getRequestId(): string {
78 // This method is called from various error handlers and MUST be kept simple and stateless.
79 if ( $this->reqId
=== null ) {
80 if ( $this->allowExternalReqID
) {
81 $id = ( $this->server
['HTTP_X_REQUEST_ID'] ??
$this->server
['UNIQUE_ID'] ??
wfRandomString( 24 ) );
83 $id = ( $this->server
['UNIQUE_ID'] ??
wfRandomString( 24 ) );
93 * Override the unique request ID. This is for sub-requests, such as jobs,
94 * that wish to use the same id but are not part of the same execution context.
96 * @param string $newId
98 public function overrideRequestId( string $newId ): void
{
99 $this->reqId
= $newId;
103 * Regenerate the request id by setting it to null, next call to `getRequestId`
104 * will refetch the request id from header/UNIQUE_ID or regenerate it.
107 public function regenerateRequestId() {
112 * Get the OpenTelemetry tracestate info
113 * Returns null when not present or AllowExternalReqID is set to false
115 * @return string|null
117 public function getTracestate(): ?
string {
118 return $this->allowExternalReqID ?
$this->server
['HTTP_TRACESTATE'] ??
null : null;
122 * Get the OpenTelemetry traceparent info,
123 * Returns null when not present or AllowExternalReqID is set to false
125 * @return string|null
127 public function getTraceparent(): ?
string {
128 return $this->allowExternalReqID ?
$this->server
['HTTP_TRACEPARENT'] ??
null : null;
132 * Return Telemetry data in form of request headers
135 public function getRequestHeaders(): array {
136 return array_filter( [
137 'tracestate' => $this->getTracestate(),
138 'traceparent' => $this->getTraceparent(),
139 'X-Request-Id' => $this->getRequestId()