Файловый менеджер - Редактировать - /var/www/html/libs.zip
Ðазад
PK ! >���� � telemetry/README.mdnu �Iw�� The `telemetry` library implements a minimal OpenTelemetry tracing client that is compatible with the OTEL data model but not compliant with the OTEL client specification. This was developed to avoid taking a dependency on the official OpenTelemetry PHP client, which was deemed too complex to integrate with MediaWiki ([T340552](https://phabricator.wikimedia.org/T340552)). `telemetry` requires a PSR-3 logger, a PSR-18 HTTP client and a PSR-17 HTTP factory. PK ! ���3� � telemetry/Tracer.phpnu �Iw�� <?php namespace Wikimedia\Telemetry; use Wikimedia\Assert\Assert; /** * @since 1.43 * @internal */ class Tracer implements TracerInterface { /** * The length of a trace ID in bytes, as specified by the OTEL specification. */ private const TRACE_ID_BYTES_LENGTH = 16; /** * The length of a span ID in bytes, as specified by the OTEL specification. */ private const SPAN_ID_BYTES_LENGTH = 8; private Clock $clock; private SamplerInterface $sampler; private ExporterInterface $exporter; private TracerState $tracerState; /** * Whether tracing has been explicitly ended by calling shutdown() on this instance. * @var bool */ private bool $wasShutdown = false; public function __construct( Clock $clock, SamplerInterface $sampler, ExporterInterface $exporter, TracerState $tracerState ) { $this->clock = $clock; $this->sampler = $sampler; $this->exporter = $exporter; $this->tracerState = $tracerState; } /** @inheritDoc */ public function createSpan( string $spanName ): SpanInterface { $activeSpanContext = $this->tracerState->getActiveSpanContext(); // Gracefully handle attempts to instrument code after shutdown() was called. if ( !$this->wasShutdown ) { Assert::precondition( $activeSpanContext !== null, 'Attempted to create a span with the currently active span as the implicit parent, ' . 'but no span was active. Use createRootSpan() to create a span with no parent (i.e. a root span).' ); } return $this->newSpan( $spanName, $activeSpanContext ); } /** @inheritDoc */ public function createRootSpan( string $spanName ): SpanInterface { return $this->newSpan( $spanName, null ); } /** @inheritDoc */ public function createSpanWithParent( string $spanName, SpanContext $parentSpanContext ): SpanInterface { return $this->newSpan( $spanName, $parentSpanContext ); } private function newSpan( string $spanName, ?SpanContext $parentSpanContext ): SpanInterface { $traceId = $parentSpanContext !== null ? $parentSpanContext->getTraceId() : $this->generateId( self::TRACE_ID_BYTES_LENGTH ); $spanId = $this->generateId( self::SPAN_ID_BYTES_LENGTH ); $sampled = $this->sampler->shouldSample( $parentSpanContext ); $spanContext = new SpanContext( $traceId, $spanId, $parentSpanContext !== null ? $parentSpanContext->getSpanId() : null, $spanName, $sampled ); if ( $this->wasShutdown || !$sampled ) { return new NoopSpan( $spanContext ); } return new Span( $this->clock, $this->tracerState, $spanContext ); } /** @inheritDoc */ public function shutdown(): void { $this->wasShutdown = true; $this->exporter->export( $this->tracerState ); } /** * Generate a valid hexadecimal string for use as a trace or span ID, with the given length in bytes. * * @param int $bytesLength The byte length of the ID * @return string The ID as a hexadecimal string */ private function generateId( int $bytesLength ): string { return bin2hex( random_bytes( $bytesLength ) ); } } PK ! �;j j telemetry/SpanContext.phpnu �Iw�� <?php namespace Wikimedia\Telemetry; use JsonSerializable; /** * Data transfer object holding data associated with a given span. * * @since 1.43 */ class SpanContext implements JsonSerializable { /** * The ID of the trace this span is part of, as a hexadecimal string. * @var string */ private string $traceId; /** * The ID of this span, as a hexadecimal string. * @var string */ private string $spanId; /** * The ID of this span, as a hexadecimal string, or `null` if this is a root span. * @var string|null */ private ?string $parentSpanId; /** * A concise description of the work represented by this span. * @see TracerInterface::createSpan() * @var string */ private string $name; /** * Whether the active sampler decided to sample and record this span. * @var bool */ private bool $sampled; /** * Key-value metadata associated with this span. * @see Span::setAttributes() * @var array */ private array $attributes = []; /** * Describes the relationship of this span to other spans within the same trace. * @see Span::setSpanKind() * @var int */ private int $spanKind = SpanInterface::SPAN_KIND_INTERNAL; /** * UNIX epoch timestamp in nanoseconds at which this span was started, * or `null` if this span was not started yet. * @var int|null */ private ?int $startEpochNanos = null; /** * UNIX epoch timestamp in nanoseconds at which this span was ended, * or `null` if this span was not ended yet. * @var int|null */ private ?int $endEpochNanos = null; public function __construct( string $traceId, string $spanId, ?string $parentSpanId, string $name, bool $sampled ) { $this->traceId = $traceId; $this->spanId = $spanId; $this->parentSpanId = $parentSpanId; $this->name = $name; $this->sampled = $sampled; } public function setEndEpochNanos( int $endEpochNanos ): void { $this->endEpochNanos = $endEpochNanos; } public function setStartEpochNanos( int $startEpochNanos ): void { $this->startEpochNanos = $startEpochNanos; } public function setSpanKind( int $spanKind ): void { $this->spanKind = $spanKind; } public function setAttributes( array $attributes ): void { $this->attributes = $attributes; } public function isSampled(): bool { return $this->sampled; } public function getSpanId(): string { return $this->spanId; } public function getTraceId(): string { return $this->traceId; } public function getParentSpanId(): ?string { return $this->parentSpanId; } public function wasStarted(): bool { return $this->startEpochNanos !== null; } public function wasEnded(): bool { return $this->endEpochNanos !== null; } public function jsonSerialize(): array { $json = [ 'traceId' => $this->traceId, 'parentSpanId' => $this->parentSpanId, 'spanId' => $this->spanId, 'name' => $this->name, 'startTimeUnixNano' => $this->startEpochNanos, 'endTimeUnixNano' => $this->endEpochNanos, 'kind' => $this->spanKind ]; if ( $this->attributes ) { $json['attributes'] = OtlpSerializer::serializeKeyValuePairs( $this->attributes ); } return $json; } /** * Check whether the given SpanContext belongs to the same span. * * @param SpanContext|null $other * @return bool */ public function equals( ?SpanContext $other ): bool { if ( $other === null ) { return false; } return $other->spanId === $this->spanId; } } PK ! �#(|K K telemetry/TracerState.phpnu �Iw�� <?php namespace Wikimedia\Telemetry; use Wikimedia\Assert\Assert; /** * Holds shared telemetry state, such as finished span data buffered for export. * * Since this data is tied to the lifetime of a given web request or process, this class is a singleton to * avoid discarding data in the case of MediaWiki service container resets. * * @since 1.43 * @internal */ class TracerState { /** * Shared tracer state for the current process or web request, `null` if uninitialized. * @var TracerState|null */ private static ?TracerState $instance = null; /** * List of already finished spans to be exported. * @var SpanContext[] */ private array $finishedSpanContexts = []; /** * Stack holding contexts for activated spans. * @var SpanContext[] */ private array $activeSpanContextStack = []; /** * Get or initialize the shared tracer state for the current process or web request. * @return TracerState */ public static function getInstance(): TracerState { self::$instance ??= new self(); return self::$instance; } /** * Reset shared tracer state. Useful for testing. * @return void */ public static function destroyInstance(): void { Assert::precondition( defined( 'MW_PHPUNIT_TEST' ), 'This function can only be called in tests' ); self::$instance = null; } /** * Add the given span to the list of finished spans. * @param SpanContext $context * @return void */ public function addSpanContext( SpanContext $context ): void { $this->finishedSpanContexts[] = $context; } /** * Get the list of finished spans. * @return SpanContext[] */ public function getSpanContexts(): array { return $this->finishedSpanContexts; } /** * Clear the list of finished spans. */ public function clearSpanContexts(): void { $this->finishedSpanContexts = []; } /** * Make the given span the active span. * @param SpanContext $spanContext Context of the span to activate * @return void */ public function activateSpan( SpanContext $spanContext ): void { $this->activeSpanContextStack[] = $spanContext; } /** * Deactivate the given span, if it was the active span. * @param SpanContext $spanContext Context of the span to deactivate * @return void */ public function deactivateSpan( SpanContext $spanContext ): void { $activeSpanContext = $this->getActiveSpanContext(); Assert::invariant( $activeSpanContext !== null && $activeSpanContext->getSpanId() === $spanContext->getSpanId(), 'Attempted to deactivate a span which is not the active span.' ); array_pop( $this->activeSpanContextStack ); } /** * Get the context of the currently active span, or `null` if no span is active. * @return SpanContext|null */ public function getActiveSpanContext(): ?SpanContext { return $this->activeSpanContextStack[count( $this->activeSpanContextStack ) - 1] ?? null; } } PK ! ��H telemetry/TracerInterface.phpnu �Iw�� <?php namespace Wikimedia\Telemetry; use Wikimedia\Assert\PreconditionException; /** * Base interface for an OpenTelemetry tracer responsible for creating spans. * @since 1.43 */ interface TracerInterface { /** * Create a span with the given name and the currently active span as the implicit parent. * This requires a span to be already active and will throw an error otherwise. * * @param string $spanName The descriptive name of this span. * Refer to the <a href="https://opentelemetry.io/docs/specs/otel/trace/api/#span">OTEL Tracing API * spec</a> for recommended naming conventions. * @return SpanInterface * @throws PreconditionException If no span was active */ public function createSpan( string $spanName ): SpanInterface; /** * Create a new root span, i.e. a span with no parent that forms the basis for a new trace. * * @param string $spanName The descriptive name of this span. * Refer to the <a href="https://opentelemetry.io/docs/specs/otel/trace/api/#span">OTEL Tracing API * spec</a> for recommended naming conventions. * @return SpanInterface */ public function createRootSpan( string $spanName ): SpanInterface; /** * Create a span with the given name and parent. * * @param string $spanName The descriptive name of this span. * Refer to the <a href="https://opentelemetry.io/docs/specs/otel/trace/api/#span">OTEL Tracing API * spec</a> for recommended naming conventions. * @param SpanContext $parentSpanContext Context of the parent span this span should be associated with. * @return SpanInterface */ public function createSpanWithParent( string $spanName, SpanContext $parentSpanContext ): SpanInterface; /** * Shut down this tracer and export collected trace data. * @return void */ public function shutdown(): void; } PK ! (��A� � telemetry/NoopSpan.phpnu �Iw�� <?php namespace Wikimedia\Telemetry; /** * An unsampled span that does nothing and persists no data. * * @since 1.43 * @internal */ class NoopSpan implements SpanInterface { private SpanContext $context; public function __construct( SpanContext $context ) { $this->context = $context; } /** @inheritDoc */ public function getContext(): SpanContext { return $this->context; } /** @inheritDoc */ public function setAttributes( array $attributes ): SpanInterface { return $this; } /** @inheritDoc */ public function setSpanKind( int $spanKind ): SpanInterface { return $this; } /** @inheritDoc */ public function start( ?int $epochNanos = null ): SpanInterface { return $this; } /** @inheritDoc */ public function end( ?int $epochNanos = null ): void { // no-op } /** @inheritDoc */ public function activate(): void { // no-op } /** @inheritDoc */ public function deactivate(): void { // no-op } } PK ! J���1 1 telemetry/ExporterInterface.phpnu �Iw�� <?php namespace Wikimedia\Telemetry; /** * Base interface for OTEL trace data exporters. * @since 1.43 * @internal */ interface ExporterInterface { /** * Export all trace data. * @param TracerState $tracerState * @return void */ public function export( TracerState $tracerState ): void; } PK ! X�M�� � telemetry/OtlpHttpExporter.phpnu �Iw�� <?php namespace Wikimedia\Telemetry; use GuzzleHttp\Psr7\Utils; use Psr\Http\Client\ClientExceptionInterface; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; use Psr\Log\LoggerInterface; /** * An {@link ExporterInterface} that exports collected data over HTTP, serialized in OTLP JSON format. * * @since 1.43 * @internal */ class OtlpHttpExporter implements ExporterInterface { private ClientInterface $client; private RequestFactoryInterface $requestFactory; private LoggerInterface $logger; /** * URI of the OTLP receiver endpoint to send data to. * @var string */ private string $endpoint; /** * Descriptive name used to identify this service in traces. * @var string */ private string $serviceName; /** * The host name of this server to be reported in traces. * @var string */ private string $hostName; public function __construct( ClientInterface $client, RequestFactoryInterface $requestFactory, LoggerInterface $logger, string $uri, string $serviceName, string $hostName ) { $this->client = $client; $this->requestFactory = $requestFactory; $this->logger = $logger; $this->endpoint = $uri; $this->serviceName = $serviceName; $this->hostName = $hostName; } /** @inheritDoc */ public function export( TracerState $tracerState ): void { $spanContexts = $tracerState->getSpanContexts(); if ( count( $spanContexts ) === 0 ) { return; } $resourceInfo = array_filter( [ 'service.name' => $this->serviceName, 'host.name' => $this->hostName, "server.socket.address" => $_SERVER['SERVER_ADDR'] ?? null, ] ); $data = [ 'resourceSpans' => [ [ 'resource' => [ 'attributes' => OtlpSerializer::serializeKeyValuePairs( $resourceInfo ) ], 'scopeSpans' => [ [ 'scope' => [ 'name' => 'org.wikimedia.telemetry', ], 'spans' => $spanContexts ] ] ] ] ]; $request = $this->requestFactory->createRequest( 'POST', $this->endpoint ) ->withHeader( 'Content-Type', 'application/json' ) ->withBody( Utils::streamFor( json_encode( $data ) ) ); try { $response = $this->client->sendRequest( $request ); if ( $response->getStatusCode() !== 200 ) { $this->logger->error( 'Failed to export trace data' ); } } catch ( ClientExceptionInterface $e ) { $this->logger->error( 'Failed to connect to exporter', [ 'exception' => $e ] ); } // Clear out finished spans after exporting them. $tracerState->clearSpanContexts(); } } PK ! �.��� � telemetry/OtlpSerializer.phpnu �Iw�� <?php namespace Wikimedia\Telemetry; /** * Utility class for serializing data in OTLP JSON format. * * @since 1.43 * @internal */ class OtlpSerializer { /** * Map of PHP types to their corresponding type name used in the OTLP JSON format. */ private const TYPE_MAP = [ 'string' => 'stringValue', 'integer' => 'intValue', 'boolean' => 'boolValue', 'double' => 'doubleValue', 'array' => 'arrayValue' ]; /** * Serialize an associative array into the format expected by the OTLP JSON format. * @param array $keyValuePairs The associative array to serialize * @return array */ public static function serializeKeyValuePairs( array $keyValuePairs ): array { $serialized = []; foreach ( $keyValuePairs as $key => $value ) { $type = gettype( $value ); if ( isset( self::TYPE_MAP[$type] ) ) { $serialized[] = [ 'key' => $key, 'value' => [ self::TYPE_MAP[$type] => $value ] ]; } } return $serialized; } } PK ! ��*� telemetry/SamplerInterface.phpnu �Iw�� <?php namespace Wikimedia\Telemetry; /** * Interface for OTEL span samplers. * @since 1.43 */ interface SamplerInterface { /** * Determine whether a newly created span should be sampled based on its parent span data. * * @param SpanContext|null $parentSpanContext Context of he parent span of the newly created span, * or `null` if the newly created span is a root span. * @return bool Whether the newly created span should be sampled. */ public function shouldSample( ?SpanContext $parentSpanContext ): bool; } PK ! ���� � telemetry/Clock.phpnu �Iw�� <?php namespace Wikimedia\Telemetry; use Wikimedia\Assert\Assert; /** * A click providing the current time in nanoseconds, backed by {@link hrtime}. * * @since 1.43 * @internal */ class Clock { /** * Timestamp to return in place of the current time, or `null` to use the current time. * @var int|null */ private static ?int $mockTime = null; /** * The reference UNIX timestamp in nanoseconds which hrtime() offsets should be added to * to derive an absolute timestamp. * @var int|null */ private ?int $referenceTime = null; public function __construct() { Assert::precondition( PHP_INT_SIZE >= 8, 'The Clock class requires 64-bit integers to support nanosecond timing' ); } /** * Get the current time, represented as the number of nanoseconds since the UNIX epoch. * @return int */ public function getCurrentNanoTime(): int { $this->referenceTime ??= (int)( 1e9 * microtime( true ) ) - hrtime( true ); return self::$mockTime ?? ( $this->referenceTime + hrtime( true ) ); } /** * Set a mock time to override the timestamp returned by {@link Clock::getCurrentNanoTime()}. * Useful for testing. * * @param int|null $epochNanos The override timestamp, or `null` to return to using the current time. * @return void */ public static function setMockTime( ?int $epochNanos ): void { Assert::precondition( defined( 'MW_PHPUNIT_TEST' ), 'This method should only be used in tests' ); self::$mockTime = $epochNanos; } } PK ! �d_27 7 telemetry/SpanInterface.phpnu �Iw�� <?php namespace Wikimedia\Telemetry; /** * Represents an OpenTelemetry span, i.e. a single operation within a trace. * * @since 1.43 * @see https://opentelemetry.io/docs/specs/otel/trace/api/#span */ interface SpanInterface { /** * Default value. Indicates that the span represents an internal operation within an application, * as opposed to an operations with remote parents or children. */ public const SPAN_KIND_INTERNAL = 1; /** * Indicates that the span covers server-side handling of a synchronous RPC or other remote request. */ public const SPAN_KIND_SERVER = 2; /** * Indicates that the span describes a request to some remote service. */ public const SPAN_KIND_CLIENT = 3; /** * Indicates that the span describes the initiators of an asynchronous request. */ public const SPAN_KIND_PRODUCER = 4; /** * Indicates that the span describes a child of an asynchronous * {@link SpanInterface::SPAN_KIND_PRODUCER} request. */ public const SPAN_KIND_CONSUMER = 5; /** * Get the context holding data for this span. * @return SpanContext */ public function getContext(): SpanContext; /** * Set attributes (arbitrary metadata) for this span. * * When deciding on the set of attributes to register as well as their naming, consider following * <a href="https://opentelemetry.io/docs/specs/semconv/general/trace/">Semantic Conventions</a> where * applicable. * * @param array $attributes key-value mapping of attribute names to values * @return SpanInterface fluent interface */ public function setAttributes( array $attributes ): SpanInterface; /** * Set the kind of this span, which describes how it relates to its parent and children * within the overarching trace. * * @param int $spanKind One of the SpanInterface::SPAN_KIND_** constants * @see https://opentelemetry.io/docs/specs/otel/trace/api/#spankind * @return SpanInterface fluent interface */ public function setSpanKind( int $spanKind ): SpanInterface; /** * Start this span, optionally specifying an override for its start time. * @param int|null $epochNanos The start time to use, or `null` to use the current time. * @return SpanInterface */ public function start( ?int $epochNanos = null ): SpanInterface; /** * End this span, optionally specifying an override for its end time. * @param int|null $epochNanos The end time to use, or `null` to use the current time. * @return void */ public function end( ?int $epochNanos = null ): void; /** * Make this span the active span. * * This will cause any spans started without specifying an explicit parent to automatically * become children of this span as long as it remains active. * * @return void */ public function activate(): void; /** * Deactivate this span. * @return void */ public function deactivate(): void; } PK ! q3nJ� � telemetry/Span.phpnu �Iw�� <?php namespace Wikimedia\Telemetry; use Wikimedia\Assert\Assert; /** * Represents an OpenTelemetry span, i.e. a single operation within a trace. * * @since 1.43 * @see https://opentelemetry.io/docs/specs/otel/trace/api/#span */ class Span implements SpanInterface { private Clock $clock; private TracerState $tracerState; private SpanContext $context; public function __construct( Clock $clock, TracerState $tracerState, SpanContext $context ) { $this->clock = $clock; $this->tracerState = $tracerState; $this->context = $context; } public function __destruct() { $this->end(); $activeSpanContext = $this->tracerState->getActiveSpanContext(); if ( $this->context->equals( $activeSpanContext ) ) { $this->deactivate(); } } /** @inheritDoc */ public function getContext(): SpanContext { return $this->context; } /** @inheritDoc */ public function setAttributes( array $attributes ): SpanInterface { $this->context->setAttributes( $attributes ); return $this; } /** @inheritDoc */ public function setSpanKind( int $spanKind ): SpanInterface { $this->context->setSpanKind( $spanKind ); return $this; } /** @inheritDoc */ public function start( ?int $epochNanos = null ): SpanInterface { Assert::precondition( !$this->context->wasStarted(), 'Cannot start a span more than once' ); $this->context->setStartEpochNanos( $epochNanos ?? $this->clock->getCurrentNanoTime() ); return $this; } /** @inheritDoc */ public function end( ?int $epochNanos = null ): void { Assert::precondition( $this->context->wasStarted(), 'Cannot end a span that has not been started' ); // Make duplicate end() calls a no-op, since it may occur legitimately, // e.g. when a span wrapped in an RAII ScopedSpan wrapper is ended explicitly. if ( !$this->context->wasEnded() ) { $this->context->setEndEpochNanos( $epochNanos ?? $this->clock->getCurrentNanoTime() ); $this->tracerState->addSpanContext( $this->context ); } } /** @inheritDoc */ public function activate(): void { $this->tracerState->activateSpan( $this->getContext() ); } /** @inheritDoc */ public function deactivate(): void { $this->tracerState->deactivateSpan( $this->getContext() ); } } PK ! ��� � � telemetry/NoopTracer.phpnu �Iw�� <?php namespace Wikimedia\Telemetry; /** * A no-op tracer that creates no-op spans and persists no data. * Useful for scenarios where tracing is disabled. * * @since 1.43 * @internal */ class NoopTracer implements TracerInterface { private SpanContext $noopSpanContext; public function __construct() { $this->noopSpanContext = new SpanContext( '', '', null, '', false ); } /** @inheritDoc */ public function createSpan( string $spanName, $parentSpan = null ): SpanInterface { return new NoopSpan( $this->noopSpanContext ); } /** @inheritDoc */ public function createRootSpan( string $spanName ): SpanInterface { return new NoopSpan( $this->noopSpanContext ); } /** @inheritDoc */ public function createSpanWithParent( string $spanName, SpanContext $parentSpanContext ): SpanInterface { return new NoopSpan( $this->noopSpanContext ); } /** @inheritDoc */ public function shutdown(): void { // no-op } } PK ! �.%y� � "