refactor sdk/api logging (#1105)

send errors/warnings/etc by default through PHP's error_log. This gives more control to administrators, since error_log can
be configured to write to any stream (file, stderr, etc). I think it's also less surprising for people trying out otel (particularly
with development PHP settings, where trigger_error often breaks an application).
Adding a configuration value to control where logs go: OTEL_PHP_LOG_DESTINATION.
This commit is contained in:
Brett McBride 2023-08-31 09:39:33 +10:00 committed by GitHub
parent 197a7a4c2c
commit 73ff5adcb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 515 additions and 254 deletions

View File

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
use OpenTelemetry\API\Globals;
use OpenTelemetry\API\Instrumentation\Configurator;
use OpenTelemetry\SDK\Trace\SpanExporter\ConsoleSpanExporterFactory;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
require __DIR__ . '/../vendor/autoload.php';
/**
* Example of globally registering <Signal>Provider instances.
* Generally this is hidden inside the SDK builder or SDK autoloading,
* but you can also do it manually. The providers are stored in
* context, and reset to previous values or defaults when the
* scope is detached.
*/
//before, a no-op provider is provided by default
echo 'Before: ' . get_class(Globals::tracerProvider()) . PHP_EOL;
$tracerProvider = TracerProvider::builder()->addSpanProcessor(
new SimpleSpanProcessor(
(new ConsoleSpanExporterFactory())->create()
)
)->build();
$configurator = Configurator::create()
->withTracerProvider($tracerProvider);
$scope = $configurator->activate();
//activated, now our $tracerProvider is globally available
echo 'During: ' . get_class(Globals::tracerProvider()) . PHP_EOL;
$scope->detach();
//after scope detached, back to default no-op providers:
echo 'After: ' . get_class(Globals::tracerProvider()) . PHP_EOL;

View File

@ -4,9 +4,6 @@ declare(strict_types=1);
namespace OpenTelemetry\Example;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use OpenTelemetry\API\LoggerHolder;
use OpenTelemetry\API\Logs\EventLogger;
use OpenTelemetry\API\Logs\LogRecord;
use OpenTelemetry\API\Signals;
@ -19,14 +16,9 @@ use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Logs\LoggerProvider;
use OpenTelemetry\SDK\Logs\LogRecordLimitsBuilder;
use OpenTelemetry\SDK\Logs\Processor\BatchLogRecordProcessor;
use Psr\Log\LogLevel;
require __DIR__ . '/../../../vendor/autoload.php';
LoggerHolder::set(
new Logger('otel-php', [new StreamHandler(STDOUT, LogLevel::DEBUG)])
);
$transport = (new GrpcTransportFactory())->create('http://collector:4317' . OtlpUtil::method(Signals::LOGS));
$exporter = new LogsExporter($transport);
$loggerProvider = new LoggerProvider(

View File

@ -4,9 +4,6 @@ declare(strict_types=1);
namespace OpenTelemetry\Example;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use OpenTelemetry\API\LoggerHolder;
use OpenTelemetry\API\Logs\EventLogger;
use OpenTelemetry\API\Logs\LogRecord;
use OpenTelemetry\Contrib\Otlp\LogsExporter;
@ -16,14 +13,9 @@ use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory;
use OpenTelemetry\SDK\Logs\LoggerProvider;
use OpenTelemetry\SDK\Logs\LogRecordLimitsBuilder;
use OpenTelemetry\SDK\Logs\Processor\SimpleLogRecordProcessor;
use Psr\Log\LogLevel;
require __DIR__ . '/../../../vendor/autoload.php';
LoggerHolder::set(
new Logger('otel-php', [new StreamHandler(STDOUT, LogLevel::DEBUG)])
);
$transport = (new OtlpHttpTransportFactory())->create('http://collector:4318/v1/logs', 'application/json');
$exporter = new LogsExporter($transport);

View File

@ -13,8 +13,6 @@ use OpenTelemetry\Contrib\Otlp\OtlpUtil;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Metrics\MetricReader\ExportingReader;
\OpenTelemetry\API\LoggerHolder::set(new \Monolog\Logger('grpc', [new \Monolog\Handler\StreamHandler('php://stderr')]));
$clock = ClockFactory::getDefault();
$reader = new ExportingReader(

View File

@ -2,10 +2,7 @@
declare(strict_types=1);
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use OpenTelemetry\API\Instrumentation\CachedInstrumentation;
use OpenTelemetry\API\LoggerHolder;
use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator;
use OpenTelemetry\Contrib\Otlp\MetricExporter;
use OpenTelemetry\SDK\Common\Export\Http\PsrTransportFactory;
@ -25,8 +22,6 @@ require __DIR__ . '/../vendor/autoload.php';
echo 'Starting SDK builder example' . PHP_EOL;
LoggerHolder::set(new Logger('grpc', [new StreamHandler('php://stderr')]));
$resource = ResourceInfoFactory::defaultResource();
$spanExporter = new InMemoryExporter();
$logRecordExporter = new \OpenTelemetry\SDK\Logs\Exporter\InMemoryExporter();

View File

@ -6,9 +6,6 @@ namespace OpenTelemetry\Example;
require __DIR__ . '/../../../vendor/autoload.php';
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use OpenTelemetry\API\LoggerHolder;
use OpenTelemetry\Contrib\Otlp\ContentTypes;
use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\SDK\Common\Export\Stream\StreamTransportFactory;
@ -16,8 +13,6 @@ use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
LoggerHolder::set(new Logger('otlp-example', [new StreamHandler('php://stderr')]));
$filename = sys_get_temp_dir() . '/traces.jsonl';
$file = fopen($filename, 'a');
$transport = (new StreamTransportFactory())->create($file, ContentTypes::NDJSON);

View File

@ -13,8 +13,6 @@ use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
\OpenTelemetry\API\LoggerHolder::set(new \Monolog\Logger('grpc', [new \Monolog\Handler\StreamHandler('php://stderr')]));
$transport = (new GrpcTransportFactory())->create('http://collector:4317' . OtlpUtil::method(Signals::TRACE));
$exporter = new SpanExporter($transport);
echo 'Starting OTLP GRPC example';

View File

@ -8,8 +8,6 @@ use OpenTelemetry\SDK\Trace\TracerProviderFactory;
require __DIR__ . '/../../../vendor/autoload.php';
\OpenTelemetry\API\LoggerHolder::set(new \Monolog\Logger('grpc', [new \Monolog\Handler\StreamHandler('php://stderr')]));
/**
* Create an otlp+grpc tracer provider from TracerProviderFactory, using environment variables as input
*/

View File

@ -6,16 +6,11 @@ namespace OpenTelemetry\Example;
require __DIR__ . '/../../../vendor/autoload.php';
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use OpenTelemetry\API\LoggerHolder;
use OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory;
use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
LoggerHolder::set(new Logger('otlp-example', [new StreamHandler('php://stderr')]));
$transport = (new OtlpHttpTransportFactory())->create('http://collector:4318/v1/traces', 'application/x-protobuf');
$exporter = new SpanExporter($transport);

View File

@ -6,8 +6,6 @@ namespace OpenTelemetry\Example;
require __DIR__ . '/../../../vendor/autoload.php';
\OpenTelemetry\API\LoggerHolder::set(new \Monolog\Logger('grpc', [new \Monolog\Handler\StreamHandler('php://stderr')]));
/**
* Create an otlp+http/protobuf tracer provider from TracerProviderFactory, using environment variables as input
*/

View File

@ -6,16 +6,11 @@ namespace OpenTelemetry\Example;
require __DIR__ . '/../../../vendor/autoload.php';
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use OpenTelemetry\API\LoggerHolder;
use OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory;
use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;
LoggerHolder::set(new Logger('otlp-example', [new StreamHandler('php://stderr')]));
$transport = (new OtlpHttpTransportFactory())->create('http://collector:4318/v1/traces', 'application/json');
$exporter = new SpanExporter($transport);

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace OpenTelemetry\Example;
require __DIR__ . '/../../../vendor/autoload.php';
require __DIR__ . '/../../vendor/autoload.php';
/**
* If you want/need to test or debug the creation of traces and spans without an instance of an exporter/collector,
@ -24,7 +24,7 @@ use OpenTelemetry\SDK\Trace\TracerProvider;
/**
* Create the log directory
*/
$logDir = __DIR__ . '/../var/log';
$logDir = __DIR__ . '/var/log';
$logFile = $logDir . '/otel.log';
if (!is_dir($logDir) && !mkdir($logDir, 0744, true) && !is_dir($logDir)) {
throw new \RuntimeException(sprintf('Directory "%s" was not created', $logDir));

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace OpenTelemetry\Example;
require __DIR__ . '/../../../vendor/autoload.php';
require __DIR__ . '/../../vendor/autoload.php';
/**
* If you want to observe or debug the span data, which is sent to an exporter/collector,
@ -29,7 +29,7 @@ use OpenTelemetry\SDK\Trace\TracerProvider;
/**
* Create the log directory
*/
$logDir = __DIR__ . '/../var/log';
$logDir = __DIR__ . '/var/log';
$logFile = $logDir . '/otel.log';
if (!is_dir($logDir) && !mkdir($logDir, 0744, true) && !is_dir($logDir)) {
throw new \RuntimeException(sprintf('Directory "%s" was not created', $logDir));

View File

@ -4,23 +4,19 @@ declare(strict_types=1);
namespace OpenTelemetry\Example;
require __DIR__ . '/../../../vendor/autoload.php';
require __DIR__ . '/../../vendor/autoload.php';
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use OpenTelemetry\API\LoggerHolder;
use OpenTelemetry\SDK\Trace\TracerProviderFactory;
use Psr\Log\LogLevel;
echo 'Starting SettingUpLogging example' . PHP_EOL;
echo 'Starting PSR-3 Logging example' . PHP_EOL;
//By default, opentelemetry's internal logging (errors, warnings, etc) will use `trigger_error`.
//You can instead provide a psr-3 logger to provide greater control of logging output:
LoggerHolder::set(
new Logger('otel-php', [new StreamHandler(STDOUT, LogLevel::DEBUG)])
);
putenv('OTEL_PHP_LOG_DESTINATION=psr3'); //or, do not set this at all.
putenv('OTEL_EXPORTER_OTLP_ENDPOINT=http://does-not-exist/endpoint'); //invalid endpoint, export will fail
putenv('OTEL_EXPORTER_OTLP_PROTOCOL=grpc');
$filename = __DIR__ . '/var/otel.log';
\OpenTelemetry\API\LoggerHolder::set(new \Monolog\Logger('otel', [new \Monolog\Handler\StreamHandler($filename)]));
$factory = new TracerProviderFactory();
$tracerProvider = $factory->create();
@ -28,3 +24,5 @@ $tracer = $tracerProvider->getTracer('io.opentelemetry.contrib.php');
$span = $tracer->spanBuilder('root-span')->startSpan();
$span->end();
$tracerProvider->shutdown();
echo sprintf("Logs written to: %s\n", $filename);

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Example;
require __DIR__ . '/../../vendor/autoload.php';
use Monolog\Logger;
use OpenTelemetry\SDK\Trace\TracerProviderFactory;
echo 'Starting Logging example' . PHP_EOL;
/**
* By default errors and warnings from the SDK itself (for example misconfiguration, exporter errors) will be sent to PHP's error_log.
* You can change that by setting OTEL_PHP_LOG_DESTINATION.
* Valid values for OTEL_PHP_LOG_DESTINATION: error_log, stdout, stderr, none, psr3, default
* (default = psr-3 if LoggerHolder::set called, otherwise error_log
*
* Note that PSR-3 logging will only work if a PSR-3 logger is registered in OpenTelemetry\API\LoggerHolder::set()
* If no PSR-3 logger is available, it will fall back to using error_log.
*/
putenv('OTEL_PHP_LOG_DESTINATION=stderr');
putenv('OTEL_EXPORTER_OTLP_ENDPOINT=http://does-not-exist/endpoint'); //invalid endpoint, export will fail
putenv('OTEL_EXPORTER_OTLP_PROTOCOL=grpc');
$factory = new TracerProviderFactory();
$tracerProvider = $factory->create();
$tracer = $tracerProvider->getTracer('io.opentelemetry.contrib.php');
$span = $tracer->spanBuilder('root-span')->startSpan();
$span->end();
$tracerProvider->shutdown();

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\API\Behavior\Internal\LogWriter;
class ErrorLogWriter implements LogWriterInterface
{
public function write($level, string $message, array $context): void
{
error_log(Formatter::format($level, $message, $context));
}
}

View File

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\API\Behavior\Internal\LogWriter;
class Formatter
{
public static function format($level, string $message, array $context): string
{
$exception = (array_key_exists('exception', $context) && $context['exception'] instanceof \Throwable)
? $context['exception']
: null;
if ($exception) {
$message = sprintf(
'OpenTelemetry: [%s] %s [exception] %s%s%s',
$level,
$message,
$exception->getMessage(),
PHP_EOL,
$exception->getTraceAsString()
);
} else {
//get calling location, skipping over trait, formatter etc
$caller = debug_backtrace()[3];
$message = sprintf(
'OpenTelemetry: [%s] %s in %s(%s)',
$level,
$message,
$caller['file'],
$caller['line'],
);
}
return $message;
}
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\API\Behavior\Internal\LogWriter;
interface LogWriterInterface
{
public function write($level, string $message, array $context): void;
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\API\Behavior\Internal\LogWriter;
class NoopLogWriter implements LogWriterInterface
{
public function write($level, string $message, array $context): void
{
//do nothing
}
}

View File

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\API\Behavior\Internal\LogWriter;
use Psr\Log\LoggerInterface;
class Psr3LogWriter implements LogWriterInterface
{
private LoggerInterface $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function write($level, string $message, array $context): void
{
$this->logger->log($level, $message, $context);
}
}

View File

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\API\Behavior\Internal\LogWriter;
class StreamLogWriter implements LogWriterInterface
{
private $stream;
public function __construct(string $destination)
{
$stream = fopen($destination, 'a');
if ($stream) {
$this->stream = $stream;
} else {
throw new \RuntimeException(sprintf('Unable to open %s for writing', $destination));
}
}
public function write($level, string $message, array $context): void
{
fwrite($this->stream, Formatter::format($level, $message, $context));
}
}

View File

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\API\Behavior\Internal;
use OpenTelemetry\API\Behavior\Internal\LogWriter\ErrorLogWriter;
use OpenTelemetry\API\Behavior\Internal\LogWriter\LogWriterInterface;
use OpenTelemetry\API\Behavior\Internal\LogWriter\NoopLogWriter;
use OpenTelemetry\API\Behavior\Internal\LogWriter\Psr3LogWriter;
use OpenTelemetry\API\Behavior\Internal\LogWriter\StreamLogWriter;
use OpenTelemetry\API\Globals;
use OpenTelemetry\API\LoggerHolder;
class LogWriterFactory
{
private const OTEL_PHP_LOG_DESTINATION = 'OTEL_PHP_LOG_DESTINATION';
public function create(): LogWriterInterface
{
$dest = Globals::configurationResolver()->getEnum(self::OTEL_PHP_LOG_DESTINATION);
//we might not have an SDK, so attempt to get from environment
if (!$dest) {
$dest = array_key_exists(self::OTEL_PHP_LOG_DESTINATION, $_SERVER)
? $_SERVER[self::OTEL_PHP_LOG_DESTINATION]
: getenv(self::OTEL_PHP_LOG_DESTINATION);
}
if (!$dest) {
$dest = ini_get(self::OTEL_PHP_LOG_DESTINATION);
}
$logger = LoggerHolder::get();
switch ($dest) {
case 'none':
return new NoopLogWriter();
case 'stderr':
return new StreamLogWriter('php://stderr');
case 'stdout':
return new StreamLogWriter('php://stdout');
case 'psr3':
if ($logger) {
return new Psr3LogWriter($logger);
}
error_log('OpenTelemetry: cannot use OTEL_PHP_LOG_DESTINATION=psr3 without providing a PSR-3 logger');
//default to error log
return new ErrorLogWriter();
case 'error_log':
return new ErrorLogWriter();
default:
if ($logger) {
return new Psr3LogWriter($logger);
}
return new ErrorLogWriter();
}
}
}

View File

@ -4,16 +4,17 @@ declare(strict_types=1);
namespace OpenTelemetry\API\Behavior\Internal;
use OpenTelemetry\API\Behavior\Internal\LogWriter\LogWriterInterface;
use Psr\Log\LogLevel;
/**
* Logging utility functions for default (error_log) logging.
* Logging utility functions for internal logging (of OpenTelemetry errors/warnings etc).
* This is not part of SDK configuration to avoid creating a dependency on SDK from any package which does logging.
* @todo this should be `@internal`, but deptrac is not happy with that.
*/
class Logging
{
private const VARIABLE_NAME = 'OTEL_LOG_LEVEL';
private const OTEL_LOG_LEVEL = 'OTEL_LOG_LEVEL';
private const DEFAULT_LEVEL = LogLevel::INFO;
private const NONE = 'none';
private const LEVELS = [
@ -32,6 +33,19 @@ class Logging
* The minimum log level. Messages with lower severity than this will be ignored.
*/
private static ?int $logLevel = null;
private static ?LogWriterInterface $writer = null;
public static function setLogWriter(LogWriterInterface $writer): void
{
self::$writer = $writer;
}
public static function logWriter(): LogWriterInterface
{
self::$writer ??= (new LogWriterFactory())->create();
return self::$writer;
}
/**
* Get level priority from level name
@ -53,30 +67,13 @@ class Logging
return self::$logLevel;
}
/**
* Map PSR-3 levels to error_log levels.
* Note that we should never use higher than E_USER_WARNING so that we do not break user applications.
*/
public static function map(string $level)
{
switch ($level) {
case LogLevel::WARNING:
case LogLevel::ERROR:
case LogLevel::CRITICAL:
case LogLevel::EMERGENCY:
return E_USER_WARNING;
default:
return E_USER_NOTICE;
}
}
private static function getLogLevel(): int
{
$level = array_key_exists(self::VARIABLE_NAME, $_SERVER)
? $_SERVER[self::VARIABLE_NAME]
: getenv(self::VARIABLE_NAME);
$level = array_key_exists(self::OTEL_LOG_LEVEL, $_SERVER)
? $_SERVER[self::OTEL_LOG_LEVEL]
: getenv(self::OTEL_LOG_LEVEL);
if (!$level) {
$level = ini_get(self::VARIABLE_NAME);
$level = ini_get(self::OTEL_LOG_LEVEL);
}
if (!$level) {
$level = self::DEFAULT_LEVEL;
@ -88,5 +85,6 @@ class Logging
public static function reset(): void
{
self::$logLevel = null;
self::$writer = null;
}
}

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace OpenTelemetry\API\Behavior;
use OpenTelemetry\API\Behavior\Internal\Logging;
use OpenTelemetry\API\LoggerHolder;
use Psr\Log\LogLevel;
trait LogsMessagesTrait
@ -17,33 +16,10 @@ trait LogsMessagesTrait
private static function doLog(string $level, string $message, array $context): void
{
$logger = LoggerHolder::get();
if ($logger !== null) {
$writer = Logging::logWriter();
if (self::shouldLog($level)) {
$context['source'] = get_called_class();
$logger->log($level, $message, $context);
} elseif (self::shouldLog($level)) {
$exception = (array_key_exists('exception', $context) && $context['exception'] instanceof \Throwable)
? $context['exception']
: null;
if ($exception) {
$message = sprintf(
'%s: %s%s%s',
$message,
$exception->getMessage(),
PHP_EOL,
$exception->getTraceAsString()
);
} else {
//get calling location, skipping over trait
$caller = debug_backtrace()[1];
$message = sprintf(
'%s(%s): %s',
$caller['file'],
$caller['line'],
$message,
);
}
trigger_error($message, Logging::map($level));
$writer->write($level, $message, $context);
}
}

View File

@ -11,4 +11,5 @@ interface ConfigurationResolverInterface
public function getBoolean(string $name): ?bool;
public function getInt(string $name): ?int;
public function getList(string $name): array;
public function getEnum(string $name): ?string;
}

View File

@ -30,4 +30,9 @@ class NoopConfigurationResolver implements ConfigurationResolverInterface
{
return [];
}
public function getEnum(string $name): ?string
{
return null;
}
}

View File

@ -32,4 +32,9 @@ class ConfigurationResolver implements ConfigurationResolverInterface
{
return Configuration::getList($name);
}
public function getEnum(string $name): ?string
{
return Configuration::getEnum($name);
}
}

View File

@ -116,4 +116,5 @@ interface Defaults
public const OTEL_PHP_INTERNAL_METRICS_ENABLED = 'false';
public const OTEL_PHP_DISABLED_INSTRUMENTATIONS = [];
public const OTEL_PHP_LOGS_PROCESSOR = 'batch';
public const OTEL_PHP_LOG_DESTINATION = 'default';
}

View File

@ -172,6 +172,11 @@ interface KnownValues
self::VALUE_NONE,
];
public const OTEL_PHP_AUTOLOAD_ENABLED = self::VALUES_BOOLEAN;
public const VALUE_ERROR_LOG = 'error_log';
public const VALUE_STDERR = 'stderr';
public const VALUE_STDOUT = 'stdout';
public const VALUE_PSR3 = 'psr3';
public const VALUE_EMPTY = '';
public const VALUE_DETECTORS_ENVIRONMENT = 'env';
public const VALUE_DETECTORS_HOST = 'host';
public const VALUE_DETECTORS_OS = 'os';
@ -192,4 +197,12 @@ interface KnownValues
self::VALUE_DETECTORS_COMPOSER,
self::VALUE_NONE,
];
public const OTEL_PHP_LOG_DESTINATION = [
self::VALUE_ERROR_LOG,
self::VALUE_STDERR,
self::VALUE_STDOUT,
self::VALUE_PSR3,
self::VALUE_EMPTY,
self::VALUE_NONE,
];
}

View File

@ -12,7 +12,7 @@ interface ValueTypes
{
/**
* General SDK Configuration
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#general-sdk-configuration
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#general-sdk-configuration
*/
public const OTEL_RESOURCE_ATTRIBUTES = VariableTypes::MAP;
public const OTEL_SERVICE_NAME = VariableTypes::STRING;
@ -22,7 +22,7 @@ interface ValueTypes
public const OTEL_TRACES_SAMPLER_ARG = VariableTypes::MIXED;
/**
* Batch Span Processor
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#batch-span-processor
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#batch-span-processor
*/
public const OTEL_BSP_SCHEDULE_DELAY = VariableTypes::INTEGER;
public const OTEL_BSP_EXPORT_TIMEOUT = VariableTypes::INTEGER;
@ -30,6 +30,7 @@ interface ValueTypes
public const OTEL_BSP_MAX_EXPORT_BATCH_SIZE = VariableTypes::INTEGER;
/**
* Batch LogRecord Processor
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#batch-logrecord-processor
*/
public const OTEL_BLRP_SCHEDULE_DELAY = VariableTypes::INTEGER;
public const OTEL_BLRP_EXPORT_TIMEOUT = VariableTypes::INTEGER;
@ -37,13 +38,13 @@ interface ValueTypes
public const OTEL_BLRP_MAX_EXPORT_BATCH_SIZE = VariableTypes::INTEGER;
/**
* Attribute Limits
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#attribute-limits
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#attribute-limits
*/
public const OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = VariableTypes::INTEGER;
public const OTEL_ATTRIBUTE_COUNT_LIMIT = VariableTypes::INTEGER;
/**
* Span Limits
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#span-limits-
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#span-limits
*/
public const OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT = VariableTypes::INTEGER;
public const OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT = VariableTypes::INTEGER;
@ -51,9 +52,15 @@ interface ValueTypes
public const OTEL_SPAN_LINK_COUNT_LIMIT = VariableTypes::INTEGER;
public const OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT = VariableTypes::INTEGER;
public const OTEL_LINK_ATTRIBUTE_COUNT_LIMIT = VariableTypes::INTEGER;
/**
* LogRecord Limits
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#logrecord-limits
*/
public const OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT = VariableTypes::INTEGER;
public const OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT = VariableTypes::INTEGER;
/**
* OTLP Exporter
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/protocol/exporter.md#configuration-options
*/
// Endpoint
public const OTEL_EXPORTER_OTLP_ENDPOINT = VariableTypes::STRING;
@ -117,8 +124,10 @@ interface ValueTypes
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#language-specific-environment-variables
*/
public const OTEL_PHP_TRACES_PROCESSOR = VariableTypes::ENUM;
public const OTEL_PHP_LOGS_PROCESSOR = VariableTypes::LIST;
public const OTEL_PHP_DETECTORS = VariableTypes::LIST;
public const OTEL_PHP_AUTOLOAD_ENABLED = VariableTypes::BOOL;
public const OTEL_PHP_LOG_DESTINATION = VariableTypes::ENUM;
public const OTEL_PHP_INTERNAL_METRICS_ENABLED = VariableTypes::BOOL;
public const OTEL_PHP_DISABLED_INSTRUMENTATIONS = VariableTypes::LIST;
}

View File

@ -12,7 +12,7 @@ interface Variables
{
/**
* General SDK Configuration
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#general-sdk-configuration
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#general-sdk-configuration
*/
public const OTEL_RESOURCE_ATTRIBUTES = 'OTEL_RESOURCE_ATTRIBUTES';
public const OTEL_SERVICE_NAME = 'OTEL_SERVICE_NAME';
@ -23,7 +23,7 @@ interface Variables
public const OTEL_SDK_DISABLED = 'OTEL_SDK_DISABLED';
/**
* Batch Span Processor
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#batch-span-processor
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#batch-span-processor
*/
public const OTEL_BSP_SCHEDULE_DELAY = 'OTEL_BSP_SCHEDULE_DELAY';
public const OTEL_BSP_EXPORT_TIMEOUT = 'OTEL_BSP_EXPORT_TIMEOUT';
@ -31,7 +31,7 @@ interface Variables
public const OTEL_BSP_MAX_EXPORT_BATCH_SIZE = 'OTEL_BSP_MAX_EXPORT_BATCH_SIZE';
/**
* Batch LogRecord Processor
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#batch-logrecord-processor
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#batch-logrecord-processor
*/
public const OTEL_BLRP_SCHEDULE_DELAY = 'OTEL_BLRP_SCHEDULE_DELAY';
public const OTEL_BLRP_EXPORT_TIMEOUT = 'OTEL_BLRP_EXPORT_TIMEOUT';
@ -39,19 +39,19 @@ interface Variables
public const OTEL_BLRP_MAX_EXPORT_BATCH_SIZE = 'OTEL_BLRP_MAX_EXPORT_BATCH_SIZE';
/**
* Attribute Limits
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#attribute-limits
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#attribute-limits
*/
public const OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = 'OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT';
public const OTEL_ATTRIBUTE_COUNT_LIMIT = 'OTEL_ATTRIBUTE_COUNT_LIMIT';
/**
* LogRecord limits
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#logrecord-limits
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#logrecord-limits
*/
public const OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT = 'OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT';
public const OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT = 'OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT';
/**
* Span Limits
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#span-limits-
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#span-limits
*/
public const OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT = 'OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT';
public const OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT = 'OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT';
@ -61,7 +61,7 @@ interface Variables
public const OTEL_LINK_ATTRIBUTE_COUNT_LIMIT = 'OTEL_LINK_ATTRIBUTE_COUNT_LIMIT';
/**
* OTLP Exporter
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/protocol/exporter.md#configuration-options
*/
// Endpoint
public const OTEL_EXPORTER_OTLP_ENDPOINT = 'OTEL_EXPORTER_OTLP_ENDPOINT';
@ -100,27 +100,28 @@ interface Variables
public const OTEL_EXPORTER_OTLP_LOGS_PROTOCOL = 'OTEL_EXPORTER_OTLP_LOGS_PROTOCOL';
/**
* Zipkin Exporter
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#zipkin-exporter
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#zipkin-exporter
*/
public const OTEL_EXPORTER_ZIPKIN_ENDPOINT = 'OTEL_EXPORTER_ZIPKIN_ENDPOINT';
public const OTEL_EXPORTER_ZIPKIN_TIMEOUT = 'OTEL_EXPORTER_ZIPKIN_TIMEOUT';
public const OTEL_EXPORTER_ZIPKIN_PROTOCOL = 'OTEL_EXPORTER_ZIPKIN_PROTOCOL';
/**
* Prometheus Exporter
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#prometheus-exporter
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#prometheus-exporter
*/
public const OTEL_EXPORTER_PROMETHEUS_HOST = 'OTEL_EXPORTER_PROMETHEUS_HOST';
public const OTEL_EXPORTER_PROMETHEUS_PORT = 'OTEL_EXPORTER_PROMETHEUS_PORT';
/**
* Exporter Selection
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#exporter-selection
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#exporter-selection
*/
public const OTEL_TRACES_EXPORTER = 'OTEL_TRACES_EXPORTER';
public const OTEL_METRICS_EXPORTER = 'OTEL_METRICS_EXPORTER';
public const OTEL_LOGS_EXPORTER = 'OTEL_LOGS_EXPORTER';
/**
* Metrics SDK Configuration
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#metrics-sdk-configuration
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#metrics-sdk-configuration
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/configuration/sdk-environment-variables.md#periodic-exporting-metricreader
*/
public const OTEL_METRICS_EXEMPLAR_FILTER = 'OTEL_METRICS_EXEMPLAR_FILTER';
public const OTEL_METRIC_EXPORT_INTERVAL = 'OTEL_METRIC_EXPORT_INTERVAL';
@ -133,6 +134,7 @@ interface Variables
*/
public const OTEL_PHP_TRACES_PROCESSOR = 'OTEL_PHP_TRACES_PROCESSOR';
public const OTEL_PHP_LOGS_PROCESSOR = 'OTEL_PHP_LOGS_PROCESSOR';
public const OTEL_PHP_LOG_DESTINATION = 'OTEL_PHP_LOG_DESTINATION';
public const OTEL_PHP_DETECTORS = 'OTEL_PHP_DETECTORS';
public const OTEL_PHP_AUTOLOAD_ENABLED = 'OTEL_PHP_AUTOLOAD_ENABLED';
public const OTEL_PHP_INTERNAL_METRICS_ENABLED = 'OTEL_PHP_INTERNAL_METRICS_ENABLED'; //whether the SDK should emit its own metrics

View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\API\Behavior\Internal;
use OpenTelemetry\API\Behavior\Internal\LogWriter\Formatter;
use PHPUnit\Framework\TestCase;
/**
* @covers \OpenTelemetry\API\Behavior\Internal\LogWriter\Formatter
*/
class FormatterTest extends TestCase
{
public function test_no_exception_contains_code_location(): void
{
$formatted = Formatter::format('error', 'hello', []);
$this->assertStringContainsString('OpenTelemetry: [error] hello in', $formatted);
}
public function test_exception_contains_stack_trace(): void
{
$formatted = Formatter::format('error', 'hello', ['exception' => new \Exception('kaboom')]);
$this->assertStringContainsString('OpenTelemetry: [error] hello [exception] kaboom', $formatted);
}
}

View File

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\API\Behavior\Internal;
use AssertWell\PHPUnitGlobalState\EnvironmentVariables;
use OpenTelemetry\API\Behavior\Internal\LogWriter\ErrorLogWriter;
use OpenTelemetry\API\Behavior\Internal\LogWriter\NoopLogWriter;
use OpenTelemetry\API\Behavior\Internal\LogWriter\Psr3LogWriter;
use OpenTelemetry\API\Behavior\Internal\LogWriter\StreamLogWriter;
use OpenTelemetry\API\Behavior\Internal\LogWriterFactory;
use OpenTelemetry\API\LoggerHolder;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
/**
* @covers \OpenTelemetry\API\Behavior\Internal\LogWriterFactory
*/
class LogWriterFactoryTest extends TestCase
{
use EnvironmentVariables;
public function tearDown(): void
{
self::restoreEnvironmentVariables();
LoggerHolder::unset();
}
/**
* @dataProvider logDestinationProvider
* @psalm-suppress ArgumentTypeCoercion
*/
public function test_log_destination_from_env(string $value, string $expected): void
{
$this->setEnvironmentVariable('OTEL_PHP_LOG_DESTINATION', $value);
$this->assertInstanceOf($expected, (new LogWriterFactory())->create());
}
public static function logDestinationProvider(): array
{
return [
['error_log', ErrorLogWriter::class],
['stdout', StreamLogWriter::class],
['stderr', StreamLogWriter::class],
['none', NoopLogWriter::class],
['', ErrorLogWriter::class],
];
}
public function test_psr3_log_destination(): void
{
LoggerHolder::set($this->createMock(LoggerInterface::class));
$this->assertInstanceOf(Psr3LogWriter::class, (new LogWriterFactory())->create());
}
}

View File

@ -6,12 +6,10 @@ namespace OpenTelemetry\Tests\Unit\API\Behavior;
use AssertWell\PHPUnitGlobalState\EnvironmentVariables;
use OpenTelemetry\API\Behavior\Internal\Logging;
use OpenTelemetry\API\Behavior\Internal\LogWriter\LogWriterInterface;
use OpenTelemetry\API\Behavior\LogsMessagesTrait;
use OpenTelemetry\API\LoggerHolder;
use PHPUnit\Framework\Exception as PHPUnitFrameworkException;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
/**
@ -21,54 +19,42 @@ class LogsMessagesTraitTest extends TestCase
{
use EnvironmentVariables;
// @var LoggerInterface|MockObject $logger
protected MockObject $logger;
protected MockObject $writer;
public function setUp(): void
{
$this->logger = $this->createMock(LoggerInterface::class);
LoggerHolder::set($this->logger);
$this->writer = $this->createMock(LogWriterInterface::class);
Logging::setLogWriter($this->writer);
}
public function tearDown(): void
{
LoggerHolder::unset();
Logging::reset();
$this->restoreEnvironmentVariables();
}
public function test_defaults_to_trigger_error_with_warning(): void
/**
* @dataProvider logProvider
*/
public function test_log(string $method, string $expectedLevel): void
{
$message = 'something went wrong';
LoggerHolder::unset();
$this->assertFalse(LoggerHolder::isSet());
$instance = $this->createInstance();
$this->expectException(PHPUnitFrameworkException::class);
$this->expectExceptionMessageMatches('/LogsMessagesTraitTest->test_defaults_to_trigger_error_with_warning()/');
$instance->run('logWarning', 'foo', ['exception' => new \Exception($message)]);
$this->writer->expects($this->once())->method('write')->with(
$this->equalTo($expectedLevel),
$this->stringContains('foo'),
$this->anything()
);
$instance->run($method, 'foo', ['exception' => new \Exception('bang')]);
}
public function test_defaults_to_trigger_error_with_error(): void
public static function logProvider(): array
{
$message = 'something went wrong';
LoggerHolder::unset();
$this->assertFalse(LoggerHolder::isSet());
$instance = $this->createInstance();
$this->expectException(PHPUnitFrameworkException::class);
$this->expectExceptionMessageMatches(sprintf('/%s/', $message));
$instance->run('logError', 'foo', ['exception' => new \Exception($message)]);
}
public function test_error_log_without_exception_contains_code_location(): void
{
LoggerHolder::unset();
$this->assertFalse(LoggerHolder::isSet());
$instance = $this->createInstance();
$this->expectException(PHPUnitFrameworkException::class);
$this->expectExceptionMessageMatches(sprintf('/%s\(/', addcslashes(__FILE__, '/')));
$instance->run('logWarning', 'no exception here');
return [
['logWarning', 'warning'],
['logError', 'error'],
];
}
/**
@ -78,7 +64,7 @@ class LogsMessagesTraitTest extends TestCase
public function test_log_methods(string $method, string $expectedLogLevel): void
{
$instance = $this->createInstance();
$this->logger->expects($this->once())->method('log')->with(
$this->writer->expects($this->once())->method('write')->with(
$this->equalTo($expectedLogLevel),
$this->equalTo('foo'),
);
@ -99,15 +85,14 @@ class LogsMessagesTraitTest extends TestCase
/**
* @dataProvider otelLogLevelProvider
*/
public function test_error_log_with_configured_otel_log_level(string $otelLogLevel, string $method, bool $expected): void
public function test_logging_respects_configured_otel_log_level(string $otelLogLevel, string $method, bool $expected): void
{
LoggerHolder::unset();
$this->setEnvironmentVariable('OTEL_LOG_LEVEL', $otelLogLevel);
$instance = $this->createInstance();
if ($expected === true) {
$this->expectException(PHPUnitFrameworkException::class);
$this->writer->expects($this->once())->method('write');
} else {
$this->assertTrue(true, 'dummy assertion');
$this->writer->expects($this->never())->method('write');
}
$instance->run($method, 'test message');
}
@ -124,8 +109,6 @@ class LogsMessagesTraitTest extends TestCase
private function createInstance(): object
{
Logging::reset();
return new class() {
use LogsMessagesTrait;
//accessor for protected trait methods

View File

@ -116,7 +116,7 @@ class ScopeTest extends TestCase
$scope['key'] = 'value';
$scope = $storage->scope();
$this->assertNotNull($scope);
$this->assertArrayHasKey('key', $scope);
$this->assertArrayHasKey('key', $scope); /** @phpstan-ignore-line */
$this->assertSame('value', $scope['key']);
unset($scope['key']);

View File

@ -8,7 +8,8 @@ use InvalidArgumentException;
use LogicException;
use Mockery;
use Mockery\Adapter\Phpunit\MockeryTestCase;
use OpenTelemetry\API\LoggerHolder;
use OpenTelemetry\API\Behavior\Internal\Logging;
use OpenTelemetry\API\Behavior\Internal\LogWriter\LogWriterInterface;
use OpenTelemetry\Context\Context;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Future\CompletedFuture;
@ -26,9 +27,8 @@ use OpenTelemetry\SDK\Metrics\StalenessHandler\ImmediateStalenessHandlerFactory;
use OpenTelemetry\SDK\Metrics\View\CriteriaViewRegistry;
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
use OpenTelemetry\Tests\Unit\SDK\Util\TestClock;
use Psr\Log\LoggerInterface;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LogLevel;
use Psr\Log\NullLogger;
/**
* @covers \OpenTelemetry\SDK\Logs\Processor\BatchLogRecordProcessor
@ -36,10 +36,13 @@ use Psr\Log\NullLogger;
class BatchLogRecordProcessorTest extends MockeryTestCase
{
private TestClock $testClock;
/** @var LogWriterInterface&MockObject $logWriter */
private LogWriterInterface $logWriter;
protected function setUp(): void
{
LoggerHolder::set(new NullLogger());
$this->logWriter = $this->createMock(LogWriterInterface::class);
Logging::setLogWriter($this->logWriter);
$this->testClock = new TestClock();
ClockFactory::setDefault($this->testClock);
@ -48,6 +51,7 @@ class BatchLogRecordProcessorTest extends MockeryTestCase
protected function tearDown(): void
{
ClockFactory::setDefault(null);
Logging::reset();
}
public function test_export_batch_size_met(): void
@ -327,22 +331,14 @@ class BatchLogRecordProcessorTest extends MockeryTestCase
$exporter->method('forceFlush')->willReturn(true);
$exporter->method('export')->willThrowException(new LogicException());
$logger = $this->createMock(LoggerInterface::class);
$logger->expects($this->once())->method('log')->with(LogLevel::ERROR);
$this->logWriter->expects($this->once())->method('write')->with(LogLevel::ERROR);
$processor = new BatchLogRecordProcessor($exporter, $this->testClock);
$record = $this->createMock(ReadWriteLogRecord::class);
$processor->onEmit($record);
$previousLogger = LoggerHolder::get();
LoggerHolder::set($logger);
try {
$processor->forceFlush();
} finally {
LoggerHolder::set($previousLogger);
}
$processor->forceFlush();
}
public function test_throwing_exporter_flush(): void
@ -371,22 +367,14 @@ class BatchLogRecordProcessorTest extends MockeryTestCase
});
$exporter->method('shutdown')->willThrowException(new LogicException());
$logger = $this->createMock(LoggerInterface::class);
$logger->expects($this->once())->method('log')->with(LogLevel::ERROR);
$this->logWriter->expects($this->once())->method('write')->with(LogLevel::ERROR);
$processor = new BatchLogRecordProcessor($exporter, $this->testClock);
$record = $this->createMock(ReadWriteLogRecord::class);
$processor->onEmit($record);
$previousLogger = LoggerHolder::get();
LoggerHolder::set($logger);
try {
$processor->forceFlush();
} finally {
LoggerHolder::set($previousLogger);
}
$processor->forceFlush();
}
public function test_throwing_exporter_flush_rethrows_in_original_caller(): void

View File

@ -7,7 +7,8 @@ namespace OpenTelemetry\Tests\Unit\SDK\Resource;
use AssertWell\PHPUnitGlobalState\EnvironmentVariables;
use Generator;
use InvalidArgumentException;
use OpenTelemetry\API\LoggerHolder;
use OpenTelemetry\API\Behavior\Internal\Logging;
use OpenTelemetry\API\Behavior\Internal\LogWriter\LogWriterInterface;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Registry;
use OpenTelemetry\SDK\Resource\ResourceDetectorInterface;
@ -15,7 +16,6 @@ use OpenTelemetry\SDK\Resource\ResourceInfo;
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
/**
* @covers \OpenTelemetry\SDK\Resource\ResourceInfoFactory
@ -24,20 +24,20 @@ class ResourceInfoFactoryTest extends TestCase
{
use EnvironmentVariables;
/** @var LoggerInterface&MockObject $logger */
private LoggerInterface $logger;
/** @var LogWriterInterface&MockObject $logWriter */
private LogWriterInterface $logWriter;
private const UNDEFINED = '__undefined';
public function setUp(): void
{
$this->logger = $this->createMock(LoggerInterface::class);
LoggerHolder::set($this->logger);
$this->logWriter = $this->createMock(LogWriterInterface::class);
Logging::setLogWriter($this->logWriter);
}
public function tearDown(): void
{
$this->restoreEnvironmentVariables();
LoggerHolder::unset();
Logging::reset();
}
public function test_empty_resource(): void
@ -189,7 +189,7 @@ class ResourceInfoFactoryTest extends TestCase
public function test_logs_warning_for_unknown_detector(): void
{
$this->logger->expects($this->once())->method('log')->with($this->equalTo('warning'));
$this->logWriter->expects($this->once())->method('write')->with($this->equalTo('warning'));
$this->setEnvironmentVariable('OTEL_PHP_DETECTORS', 'does-not-exist');
ResourceInfoFactory::defaultResource();

View File

@ -9,7 +9,8 @@ use InvalidArgumentException;
use LogicException;
use Mockery;
use Mockery\Adapter\Phpunit\MockeryTestCase;
use OpenTelemetry\API\LoggerHolder;
use OpenTelemetry\API\Behavior\Internal\Logging;
use OpenTelemetry\API\Behavior\Internal\LogWriter\LogWriterInterface;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
@ -30,9 +31,8 @@ use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor;
use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessorBuilder;
use OpenTelemetry\SDK\Trace\SpanProcessorInterface;
use OpenTelemetry\Tests\Unit\SDK\Util\TestClock;
use Psr\Log\LoggerInterface;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LogLevel;
use Psr\Log\NullLogger;
/**
* @covers \OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor
@ -40,10 +40,13 @@ use Psr\Log\NullLogger;
class BatchSpanProcessorTest extends MockeryTestCase
{
private TestClock $testClock;
/** @var LogWriterInterface&MockObject $logWriter */
private LogWriterInterface $logWriter;
protected function setUp(): void
{
LoggerHolder::set(new NullLogger());
$this->logWriter = $this->createMock(LogWriterInterface::class);
Logging::setLogWriter($this->logWriter);
$this->testClock = new TestClock();
ClockFactory::setDefault($this->testClock);
@ -52,6 +55,7 @@ class BatchSpanProcessorTest extends MockeryTestCase
protected function tearDown(): void
{
ClockFactory::setDefault(null);
Logging::reset();
}
public function test_export_batch_size_met(): void
@ -373,8 +377,7 @@ class BatchSpanProcessorTest extends MockeryTestCase
$exporter->method('forceFlush')->willReturn(true);
$exporter->method('export')->willThrowException(new LogicException());
$logger = $this->createMock(LoggerInterface::class);
$logger->expects($this->once())->method('log')->with(LogLevel::ERROR);
$this->logWriter->expects($this->once())->method('write')->with(LogLevel::ERROR);
$processor = new BatchSpanProcessor($exporter, $this->testClock);
@ -382,14 +385,7 @@ class BatchSpanProcessorTest extends MockeryTestCase
$processor->onStart($span, Context::getCurrent());
$processor->onEnd($span);
$previousLogger = LoggerHolder::get();
LoggerHolder::set($logger);
try {
$processor->forceFlush();
} finally {
LoggerHolder::set($previousLogger);
}
$processor->forceFlush();
}
public function test_throwing_exporter_flush(): void
@ -420,8 +416,7 @@ class BatchSpanProcessorTest extends MockeryTestCase
});
$exporter->method('shutdown')->willThrowException(new LogicException());
$logger = $this->createMock(LoggerInterface::class);
$logger->expects($this->once())->method('log')->with(LogLevel::ERROR);
$this->logWriter->expects($this->once())->method('write')->with(LogLevel::ERROR);
$processor = new BatchSpanProcessor($exporter, $this->testClock);
@ -429,14 +424,7 @@ class BatchSpanProcessorTest extends MockeryTestCase
$processor->onStart($span, Context::getCurrent());
$processor->onEnd($span);
$previousLogger = LoggerHolder::get();
LoggerHolder::set($logger);
try {
$processor->forceFlush();
} finally {
LoggerHolder::set($previousLogger);
}
$processor->forceFlush();
}
public function test_throwing_exporter_flush_rethrows_in_original_caller(): void

View File

@ -8,7 +8,8 @@ use LogicException;
use Mockery;
use Mockery\Adapter\Phpunit\MockeryTestCase;
use Mockery\MockInterface;
use OpenTelemetry\API\LoggerHolder;
use OpenTelemetry\API\Behavior\Internal\Logging;
use OpenTelemetry\API\Behavior\Internal\LogWriter\LogWriterInterface;
use OpenTelemetry\API\Trace\SpanContext;
use OpenTelemetry\API\Trace\SpanContextInterface;
use OpenTelemetry\API\Trace\SpanContextValidator;
@ -20,9 +21,8 @@ use OpenTelemetry\SDK\Trace\ReadWriteSpanInterface;
use OpenTelemetry\SDK\Trace\SpanExporterInterface;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\Tests\Unit\SDK\Util\SpanData;
use Psr\Log\LoggerInterface;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LogLevel;
use Psr\Log\NullLogger;
/**
* @covers \OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor
@ -39,13 +39,16 @@ class SimpleSpanProcessorTest extends MockeryTestCase
/** @var MockInterface&ReadableSpanInterface */
private $readableSpan;
/** @var LogWriterInterface&MockObject $logWriter */
private LogWriterInterface $logWriter;
private SpanContextInterface $sampledSpanContext;
private SpanContextInterface $nonSampledSpanContext;
protected function setUp(): void
{
LoggerHolder::set(new NullLogger());
$this->logWriter = $this->createMock(LogWriterInterface::class);
Logging::setLogWriter($this->logWriter);
$this->readWriteSpan = Mockery::mock(ReadWriteSpanInterface::class);
$this->readableSpan = Mockery::mock(ReadableSpanInterface::class);
@ -61,6 +64,11 @@ class SimpleSpanProcessorTest extends MockeryTestCase
$this->simpleSpanProcessor = new SimpleSpanProcessor($this->spanExporter);
}
public function tearDown(): void
{
Logging::reset();
}
public function test_on_start(): void
{
$this->simpleSpanProcessor->onStart($this->readWriteSpan, Context::getRoot());
@ -143,23 +151,15 @@ class SimpleSpanProcessorTest extends MockeryTestCase
$exporter->method('forceFlush')->willReturn(true);
$exporter->method('export')->willThrowException(new LogicException());
$logger = $this->createMock(LoggerInterface::class);
$logger->expects($this->once())->method('log')->with(LogLevel::ERROR);
$this->logWriter->expects($this->once())->method('write')->with(LogLevel::ERROR);
$processor = new SimpleSpanProcessor($exporter);
$this->readableSpan->expects('getContext')->andReturn($this->sampledSpanContext);
$this->readableSpan->expects('toSpanData')->andReturn(new SpanData());
$previousLogger = LoggerHolder::get();
LoggerHolder::set($logger);
try {
$processor->onStart($this->readWriteSpan, Context::getCurrent());
$processor->onEnd($this->readableSpan);
} finally {
LoggerHolder::set($previousLogger);
}
$processor->onStart($this->readWriteSpan, Context::getCurrent());
$processor->onEnd($this->readableSpan);
}
public function test_throwing_exporter_flush(): void

View File

@ -9,7 +9,8 @@ use Exception;
use Mockery;
use Mockery\Adapter\Phpunit\MockeryTestCase;
use Mockery\MockInterface;
use OpenTelemetry\API\LoggerHolder;
use OpenTelemetry\API\Behavior\Internal\Logging;
use OpenTelemetry\API\Behavior\Internal\LogWriter\LogWriterInterface;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\API\Trace\NonRecordingSpan;
use OpenTelemetry\API\Trace\SpanContext;
@ -38,7 +39,7 @@ use OpenTelemetry\SDK\Trace\SpanLimitsBuilder;
use OpenTelemetry\SDK\Trace\SpanProcessorInterface;
use OpenTelemetry\SDK\Trace\StatusData;
use OpenTelemetry\Tests\Unit\SDK\Util\TestClock;
use Psr\Log\LoggerInterface;
use PHPUnit\Framework\MockObject\MockObject;
use function range;
use function str_repeat;
@ -58,7 +59,8 @@ class SpanTest extends MockeryTestCase
/** @var MockInterface&SpanProcessorInterface */
private $spanProcessor;
private $logger;
/** @var LogWriterInterface&MockObject $logWriter */
private LogWriterInterface $logWriter;
private IdGeneratorInterface $idGenerator;
private ResourceInfo $resource;
@ -98,14 +100,15 @@ class SpanTest extends MockeryTestCase
);
ClockFactory::setDefault($this->testClock);
$this->logger = $this->createMock(LoggerInterface::class);
LoggerHolder::set($this->logger);
$this->logWriter = $this->createMock(LogWriterInterface::class);
Logging::setLogWriter($this->logWriter);
}
protected function tearDown(): void
{
ClockFactory::setDefault(null);
LoggerHolder::unset();
Logging::reset();
// LoggerHolder::unset();
}
// region API
@ -496,8 +499,8 @@ class SpanTest extends MockeryTestCase
*/
public function test_set_attribute_drops_non_homogeneous_array(array $values): void
{
$this->logger->expects($this->once())
->method('log')
$this->logWriter->expects($this->once())
->method('write')
->with(
$this->equalTo('warning'),
$this->stringContains('non-homogeneous')

View File

@ -5,14 +5,15 @@ declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\SDK\Trace;
use AssertWell\PHPUnitGlobalState\EnvironmentVariables;
use OpenTelemetry\API\LoggerHolder;
use OpenTelemetry\API\Behavior\Internal\Logging;
use OpenTelemetry\API\Behavior\Internal\LogWriter\LogWriterInterface;
use OpenTelemetry\API\Trace\NoopTracerProvider;
use OpenTelemetry\SDK\Trace\ExporterFactory;
use OpenTelemetry\SDK\Trace\SamplerFactory;
use OpenTelemetry\SDK\Trace\SpanProcessorFactory;
use OpenTelemetry\SDK\Trace\TracerProviderFactory;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
/**
* @covers \OpenTelemetry\SDK\Trace\TracerProviderFactory
@ -21,17 +22,18 @@ class TracerProviderFactoryTest extends TestCase
{
use EnvironmentVariables;
private $logger;
/** @var LogWriterInterface&MockObject $logWriter */
private LogWriterInterface $logWriter;
public function setUp(): void
{
$this->logger = $this->createMock(LoggerInterface::class);
LoggerHolder::set($this->logger);
$this->logWriter = $this->createMock(LogWriterInterface::class);
Logging::setLogWriter($this->logWriter);
}
public function tearDown(): void
{
LoggerHolder::unset();
Logging::reset();
$this->restoreEnvironmentVariables();
}
@ -64,7 +66,7 @@ class TracerProviderFactoryTest extends TestCase
$spanProcessorFactory->expects($this->once())
->method('create')
->willThrowException(new \InvalidArgumentException('foo'));
$this->logger->expects($this->atLeast(3))->method('log');
$this->logWriter->expects($this->atLeast(3))->method('write');
$factory = new TracerProviderFactory($exporterFactory, $samplerFactory, $spanProcessorFactory);
$factory->create();