OpenTelemetry - #350
Open
fballiano wants to merge 43 commits into
Open
Conversation
…Telemetry - Record PHP errors (warnings, notices, deprecations) as span events in mageCoreErrorHandler() using null-safe chaining for zero overhead when OTel is disabled - Add http.route and admin user context (enduser.id, maho.admin_user) to the root span after dispatch - Ensure telemetry flush is always deferred after response by calling fastcgi_finish_request() on error paths too
Bug fixes: - Remove duplicate root span (Profiler + App::run both created http.request) - Fix span stack never popped: Span::end() now calls Tracer::popSpan() - Fix Logger infinite recursion: use error_log() instead of Mage::log() in createLogger() catch block to prevent re-entrant stack overflow - Fix Profiler::reset() not cleaning $_spans, leaving stale span objects - Remove redundant _getHeaders() method, call helper directly New tracing spans via Profiler::start/stop: - Cache operations: load, save, remove, clean, flush - Payment processing: authorize, capture, refund, void - Cron job execution with job_code and model attributes - Email sending with template_id and recipient_count - Index reindexing with index code and name - Image processing with dimensions and destination Update copyright years to 2025-2026 for all OpenTelemetry files.
…K version - Convert TraceContext from Monolog Handler to Processor so trace_id/span_id are actually visible to subsequent handlers (was silently lost before) - Remove no-op payment profiler spans in authorize/capture/refund/void that measured nothing (start+stop back-to-back with no work in between) - Fix telemetry.sdk.version reporting actual SDK version instead of 'php' - Cast ob_get_length() to int for proper OTel attribute typing - Fix copyright years to 2026 on all new OpenTelemetry module files - Restore original whitespace in Mage_Core_Model_Abstract
Wrap authorize/capture/refund/void gateway calls with Profiler spans in Mage_Sales_Model_Order_Payment where the actual method dispatch happens. This traces ALL payment methods (core and 3rd party) since they all flow through this single orchestrator. Uses try/finally to ensure spans are closed even when gateway methods throw exceptions.
- Mark HTTP spans as 'error' for 5xx status codes per OTel semantic conventions (TracedClient and App root span were always set to 'ok') - Cache tracing availability in Profiler to avoid repeated Mage::startSpan() calls when OTel is disabled (isset(null) => false caused re-invocation on every Profiler::start()) - Remove unused TransportFactoryInterface import from Tracer
- Activate spans in OTel Context so child spans nest correctly under parent spans (without this, all spans were flat/disconnected roots) - Detach scope on span end to restore parent context - Remove aggressive $_tracingAvailable cache from Profiler that permanently disabled tracing when early bootstrap calls returned null - Fix model alias case mismatch (http_tracedClient -> http_tracedclient) - Remove unused init() method from Tracer
Ensure Profiler::stop() always executes even when exceptions are thrown, preventing orphaned spans. Also strip query strings from traced URLs to avoid leaking sensitive parameters, and use consistent dot separators for profiler keys.
…Stan - End orphaned spans in reverse order before flushing TracerProvider - Set span error status when DB query exceptions are recorded - Add PHPStan class.notFound ignore for optional OTel SDK dependency - Add @var annotation for pass-by-reference type narrowing
…lback Use dot separator consistently in profiler keys for OTel span naming instead of mixing :: and dot. Add ?: 200 fallback for http_response_code() which returns false in CLI context.
Replace $e->getMessage() with $e::class in span setStatus() calls to avoid leaking sensitive information (SQL queries, bind values, credentials) into telemetry. Remove recordException() from DB adapter to prevent full exception messages containing SQL from reaching the trace backend. Add explicit (string) cast for Select objects passed to _getOperationType().
Contributor
Author
Profiler timer naming inconsistencyThe
We should normalize all profiler timer names across the codebase to use a single convention (e.g., lowercase with |
- Remove unused SimpleSpanProcessor import from Tracer - Restore store context attributes (store_id, store_code, website_id) - Restore admin user context (enduser.id) without username PII - Remove http.url and http.user_agent (PII concerns), keep http.target - Remove unreachable cron area detection (CLI doesn't go through App::run) - Remove BLOCK: prefix from Profiler span whitelist (too noisy, 50-100+/page) - Move $_spanPrefixes to top of Profiler class with other static properties - Restructure App::run() with try/catch/finally for robust span lifecycle - Add justification comments for error_log() usage during early bootstrap
…ings Move package installation checks into the base Fieldset and Heading renderers so any group or heading field with <mandatory_package> in its XML automatically shows a warning when the package is missing. Remove the dedicated Packagecheck subclass that required a custom frontend_model. PayPal SFTP heading keeps mandatory_package on the heading level, OpenTelemetry uses it on the group level.
# Conflicts: # .phpstan.dist.neon # .phpstorm.meta.php/blocks.meta.php # .phpstorm.meta.php/helpers.meta.php # .phpstorm.meta.php/models.meta.php # app/code/core/Mage/Adminhtml/Block/System/Config/Form/Field/Heading/Packagecheck.php # app/code/core/Mage/Catalog/Model/Product/Image.php # app/code/core/Mage/Core/Block/Abstract.php # app/code/core/Mage/Cron/Model/Observer.php # app/code/core/Mage/Dataflow/Model/Convert/Adapter/Http/Curl.php # app/code/core/Mage/Paypal/Model/Api/Nvp.php # app/code/core/Mage/Paypal/Model/Ipn.php # app/code/core/Mage/Paypal/Model/Payflowpro.php # app/code/core/Mage/Paypal/etc/system.xml # composer.json
…r decryption, telemetry data scrubbing - Removed fastcgi_finish_request() on the error path so error pages render under FPM/FrankenPHP, and removed the premature root-span end so the http.request span covers the full request lifecycle - Replaced the profiler's flat span map with a per-name LIFO stack so re-entrant same-name timers no longer orphan spans - Cached permanent tracer initialization failures in Mage::getTracer() to stop per-call re-initialization and log spam on hot paths - Added backend_model to the auth_header config node so the OTLP Authorization header is decrypted at runtime - Added missing image.process, index.reindex and payment. span prefixes - Made Span trace-context getters silent on failure (they sit on the Monolog processor path and must not log) and added a re-entrancy guard around the php.error span event in mageCoreErrorHandler - Limited error.message export in php.error span events to fatal-class severities to avoid leaking credential-bearing warning text - Steered credentials away from the plaintext custom_headers field via its comment, consolidated SPDX headers in new files, and switched two Span error_log() calls to Mage::log()
…nfig, noise controls, CLI traces and commerce events
- Migrated all span attributes to the stable OpenTelemetry semantic conventions: http.request.method, url.path/url.full/url.scheme, http.response.status_code, server.address/port, db.system.name, db.query.text, db.operation.name, db.collection.name, db.namespace, code.file.path/code.line.number
- Set span kinds (SERVER on the request root span, CLIENT on DB queries and outgoing HTTP) so service graphs and RED metrics work in tracing backends
- Renamed the root span to "{method} {module/controller/action}" after routing and DB spans to "{operation} {table}" per semconv low-cardinality naming
- Added standard OTEL_* environment variable support (OTEL_SDK_DISABLED, OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT/_TRACES_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, OTEL_TRACES_SAMPLER/_ARG, OTEL_BSP_*) with admin configuration as fallback
- Added noise controls: a Trace Block Rendering toggle and an Excluded Paths list; exclusion is decided at tracer initialization so bootstrap query spans never leak for excluded requests
- Each CLI command now runs as its own trace (command name only, arguments never recorded since they can contain secrets), with cron jobs nesting under maho cron:run
- Added commerce span events via attribute observers: order placed, add to cart, checkout success and customer login (pseudonymous ids only, no PII)
- Outgoing HTTP requests now also propagate W3C baggage (store code and currency); url.full is recomposed without query string, fragment or userinfo so embedded credentials never reach a span
…d module documentation - Incoming W3C traceparent/tracestate headers can now continue an upstream trace, gated behind a default-off Trust Incoming Trace Headers flag (only for use behind trusted proxies); sampling is parent-based so the caller's decision is respected - Optional Server-Timing response header (default off) exposes the W3C trace context to browser RUM tooling for frontend-to-backend correlation - Optional OTLP log export ships Monolog records (already tagged with trace ids) to /v1/logs via the official open-telemetry/opentelemetry-logger-monolog bridge; the logger cache is rebuilt after tracer initialization and on Mage::reset() so handlers never reference a stale tracer - Optional OTLP metric export with delta temporality: http.server.request.duration histogram plus maho.orders, maho.order.revenue and maho.cart.additions counters; failed dispatches record status 500 instead of a bogus 200 - OTLP transports use a single retry so a struggling collector holds PHP workers as briefly as possible; documented the worst-case flush behavior - Span, Tracer and TracedClient are now plain classes instead of extending Mage_Core_Model_Abstract - Added Pest coverage (15 tests) for env-var precedence, per-signal endpoint derivation, sampler gating, header merging, path exclusion and the no-op safety contract of the null span/tracer - Added module README covering setup (including the required nyholm/psr7 PSR-17 factories), configuration, span reference and data-safety guarantees - Verified end-to-end against a real SDK install: traces, logs and metrics all reach their OTLP endpoints and trusted incoming traceparent is continued
The lowercase model alias resolved to Maho_OpenTelemetry_Model_Http_Tracedclient, which only loads on case-insensitive filesystems; on Linux the factory returned nothing and PHPStan flagged the invalid type. The class is plain (not a rewritable Mage model), so direct instantiation is the correct construction path.
The LiteSpeed SAPI has supported fastcgi_finish_request() since PHP 7.4, but the SAPI allow-list only covered PHP-FPM and FrankenPHP, so LiteSpeed fell back to flush() and held the client connection until script end. The function_exists() guard keeps older LiteSpeed builds on the fallback path.
# Conflicts: # .phpstan.dist.neon # app/code/core/Mage/Core/Model/App.php # app/code/core/Mage/Core/Model/Email/Template.php # app/code/core/Mage/Cron/Model/Observer.php # app/code/core/Mage/Directory/Model/Currency/Import/Currencyconverterapi.php # app/code/core/Mage/Directory/Model/Currency/Import/Fixerio.php # composer.json # lib/MahoCLI/Commands/BaseMahoCommand.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.