VOOZH about

URL: https://deepwiki.com/friendsofhyperf/components/2.3-aop-based-instrumentation

⇱ AOP-Based Instrumentation | friendsofhyperf/components | DeepWiki


Loading...
Last indexed: 14 February 2026 (15d5ca)
Menu

AOP-Based Instrumentation

Purpose and Scope

This document describes the aspect-oriented programming (AOP) approach used by the Sentry integration to instrument Hyperf applications transparently. AOP allows the Sentry component to intercept method calls across database connections, Redis operations, RPC clients, HTTP requests, Elasticsearch queries, and coroutine creation without requiring developers to modify application code.

For information about the broader tracing architecture and trace context propagation, see Distributed Tracing Architecture. For details on event-based instrumentation and the EventHandleListener, see Event Lifecycle and EventHandleListener. For coroutine context management, see Coroutine Context Management and SentryContext.

Instrumentation Architecture

The Sentry component registers multiple aspect classes through ConfigProvider that intercept specific method calls throughout the Hyperf framework. Each aspect implements the AbstractAspect pattern from hyperf/di, declaring target classes and methods in its $classes array.

Aspect Registration Flow


Sources: src/sentry/src/ConfigProvider.php21-52 src/sentry/src/Tracing/Aspect/DbConnectionAspect.php25-29 src/sentry/src/Tracing/Aspect/RedisConnectionAspect.php27-29 src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php38-40

Each aspect's process() method wraps the original method execution, typically following this pattern:

  1. Check if the corresponding tracing span is enabled via Feature::isTracingSpanEnabled()
  2. Execute the original method via ProceedingJoinPoint::process()
  3. Extract server information (host, port) from the connection object
  4. Store server information in SentryContext for later use by the EventHandleListener
  5. Create spans with operation metadata using the trace() helper function

Database Instrumentation

The database instrumentation consists of two aspects that work together to capture connection information and query execution.

DbConnectionAspect - Server Information Extraction

DbConnectionAspect intercepts PDO connection creation to extract and cache server addresses and ports. It uses a WeakMap to associate PDO connections with their server configuration.

Database Server Information Flow


Sources: src/sentry/src/Tracing/Aspect/DbConnectionAspect.php25-68 src/sentry/src/SentryContext.php117-135

The aspect intercepts three methods:

MethodPurposeLine Reference
Connector::createPdoConnectionExtract host/port from DSN string and cache in WeakMapsrc/sentry/src/Tracing/Aspect/DbConnectionAspect.php45-53
Connection::getPdoForSelectRetrieve cached server info and store in SentryContextsrc/sentry/src/Tracing/Aspect/DbConnectionAspect.php56-65
Connection::getPdoRetrieve cached server info and store in SentryContextsrc/sentry/src/Tracing/Aspect/DbConnectionAspect.php56-65

The DSN parsing uses a regex pattern /host=([^;]+);port=(\d+);?/ to extract connection details src/sentry/src/Tracing/Aspect/DbConnectionAspect.php47-51

DbAspect - Query Tracing

DbAspect instruments the Hyperf\DB\DB class to create spans for raw database queries executed through the DB facade.

Sources: src/sentry/src/Tracing/Aspect/DbAspect.php36-135

The aspect extracts:

  • Database system (driver)
  • Database name (database)
  • Table name (parsed from SQL via SqlParser::parse())
  • Operation name (SELECT, INSERT, UPDATE, etc.)
  • Connection pool metrics (max connections, idle connections, current connections)
  • SQL bindings (when tracing_tags.db.sql.bindings is enabled)

Redis Instrumentation

Redis instrumentation similarly uses a two-aspect approach to capture connection information and command execution.

RedisConnectionAspect - Server Information Extraction

RedisConnectionAspect extracts Redis server addresses from Redis, RedisSentinel, and RedisCluster connections. For cluster connections, it calculates the correct node using the RedisClusterKeySlot utility.

Redis Cluster Node Resolution


Sources: src/sentry/src/Tracing/Aspect/RedisConnectionAspect.php27-87 src/sentry/src/Util/RedisClusterKeySlot.php51-68

The RedisClusterKeySlot utility implements the CRC16 algorithm to calculate which cluster slot (0-16383) a key belongs to, accounting for hash tags like {tag} in Redis keys src/sentry/src/Util/RedisClusterKeySlot.php51-68 The calculated slot is then matched against the cluster's slot ranges obtained from CLUSTER SLOTS to determine the actual node.

RedisAspect - Command Tracing (Deprecated)

RedisAspect is marked as deprecated since v3.1 and will be removed in v3.2. It instruments Hyperf\Redis\Redis::__call but only if the newer CommandExecuted event class doesn't exist src/sentry/src/Tracing/Aspect/RedisAspect.php29-54 This aspect is superseded by event-based instrumentation through EventHandleListener.

Sources: src/sentry/src/Tracing/Aspect/RedisAspect.php36-95

RPC Instrumentation

RPC instrumentation involves three aspects that capture both JSON-RPC and gRPC client calls, extract server endpoints, and inject trace headers.

RpcAspect - JSON-RPC Client Tracing

RpcAspect intercepts JSON-RPC client methods in two phases:

Phase 1: RPC Path Generation

  • Intercepts AbstractServiceClient::__generateRpcPath to prepare span context
  • Builds SpanContext with RPC metadata (system, service, method)
  • Stores span context in SentryContext for retrieval during the send phase

Phase 2: RPC Request Sending

  • Intercepts RpcClient\Client::send to execute the actual trace
  • Retrieves span context from SentryContext
  • Injects trace carrier into Rpc\Context for propagation
  • Records server address/port from SentryContext

Sources: src/sentry/src/Tracing/Aspect/RpcAspect.php39-131 src/sentry/src/SentryContext.php147-160

The aspect determines the RPC system by examining the protocol string:

  • multiplex-rpc for multiplex protocols
  • jsonrpc for JSON-RPC protocols
  • rpc as fallback

This follows OpenTelemetry semantic conventions for RPC spans src/sentry/src/Tracing/Aspect/RpcAspect.php73-87

RpcEndpointAspect - Server Endpoint Extraction

RpcEndpointAspect extracts server endpoint information from various RPC transporter implementations by intercepting connection/socket retrieval methods.

Target MethodConnection TypeExtraction StrategyLine Reference
RpcMultiplex\SocketFactory::getMultiplex Socketsocket->getName(), socket->getPort()src/sentry/src/Tracing/Aspect/RpcEndpointAspect.php41-44
JsonRpc\JsonRpcHttpTransporter::getNodeLoad Balancer Nodenode->host, node->portsrc/sentry/src/Tracing/Aspect/RpcEndpointAspect.php46-49
JsonRpc\JsonRpcPoolTransporter::getConnectionPool ConnectionAccess internal socket via closure, get host/port from SocketOptionInterfacesrc/sentry/src/Tracing/Aspect/RpcEndpointAspect.php51-62

Sources: src/sentry/src/Tracing/Aspect/RpcEndpointAspect.php23-65

GrpcAspect - gRPC Client Tracing

GrpcAspect instruments gRPC client calls by intercepting BaseClient::_simpleRequest for both Hyperf's GrpcClient and the standard Grpc\BaseStub.

The aspect:

  1. Extracts server address and port using closure access to private properties
  2. Checks if a parent span exists and is sampled
  3. Injects sentry-trace and baggage headers into gRPC request options
  4. Creates a span with rpc.client operation type

Sources: src/sentry/src/Tracing/Aspect/GrpcAspect.php28-84


Sources: src/sentry/src/Tracing/Aspect/GrpcAspect.php44-83

The header injection ensures distributed tracing works across gRPC service boundaries src/sentry/src/Tracing/Aspect/GrpcAspect.php67-73

HTTP Client Instrumentation

GuzzleHttpClientAspect - HTTP Request Tracing

GuzzleHttpClientAspect instruments the Guzzle HTTP client by intercepting Client::transfer to capture detailed HTTP request/response metrics.

HTTP Client Instrumentation Flow


Sources: src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php38-203

Key features of HTTP client instrumentation:

  1. Opt-out mechanism: Requests can be excluded from tracing by setting no_sentry_tracing option to true in either request options or Guzzle client config src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php65-69

  2. Header injection: Trace context headers are injected into request headers to enable distributed tracing src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php76-82

  3. Stats callback override: The aspect overrides or wraps the on_stats callback to capture timing and metadata from TransferStats src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php86-138

  4. Response body handling: Response bodies are captured selectively:

    • Only textual content types (text/*, application/json, application/xml, etc.)
    • Maximum 8KB read (MAX_RESPONSE_BODY_SIZE = 8192)
    • Truncated with "… [truncated]" suffix if larger
    • Stream position preserved via seek() to avoid breaking the request flow
    • Streamed responses return [Streamed Response] placeholder

Sources: src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php150-202

  1. Recorded metrics:
Metric CategorySpan Data KeysDescription
Requesthttp.request.method, http.request.full_url, http.request.path, http.request.scheme, http.request.host, http.request.portHTTP method, URLs, and addressing
Requesthttp.request.body.size, http.request.headers, http.request.user_agentRequest payload metadata
Responsehttp.response.status_code, http.response.reason, http.response.headersResponse status and headers
Responsehttp.response.body.size, http.response.body.contents (optional)Response payload
TimingdurationTotal transfer time in milliseconds
Serverserver.address, server.portTarget server endpoint
Systemhttp.system, http.guzzle.config, http.guzzle.optionsGuzzle-specific metadata

Sources: src/sentry/src/Tracing/Aspect/GuzzleHttpClientAspect.php89-129

Elasticsearch Instrumentation

Elasticsearch instrumentation uses two aspects to capture both ES 7.x and ES 8.x client operations.

ElasticsearchAspect - Query Method Tracing

ElasticsearchAspect intercepts high-level Elasticsearch operations like search, index, bulk, count, etc., creating spans for each operation.

Supported methods across both Elasticsearch versions:

ES 7.x ClassES 8.x ClassMethods
Elasticsearch\ClientElastic\Elasticsearch\Traits\ClientEndpointsTraitbulk, count, create, get, getSource, index, mget, msearch, scroll, search, update, updateByQuery

Sources: src/sentry/src/Tracing/Aspect/ElasticsearchAspect.php26-53

Each operation creates a db.query span with:

  • db.system: elasticsearch
  • db.operation.name: <method_name>
  • arguments: JSON-encoded method arguments
  • Additional server data from SentryContext::getElasticsearchSpanData()

ElasticsearchRequestAspect - Server Information Extraction

ElasticsearchRequestAspect extracts server endpoint information by intercepting low-level request execution methods.

Elasticsearch Version-Specific Interception


Sources: src/sentry/src/Tracing/Aspect/ElasticsearchRequestAspect.php24-86

For ES 8.x, the aspect intercepts sendRequest() and extracts server information directly from the PSR-7 RequestInterface before execution src/sentry/src/Tracing/Aspect/ElasticsearchRequestAspect.php39-49

For ES 7.x, the aspect intercepts performRequest() and extracts server information after execution from the last connection's request info src/sentry/src/Tracing/Aspect/ElasticsearchRequestAspect.php52-63

The extracted data includes:

  • server.address
  • server.port
  • http.request.method
  • url.full (constructed as scheme://host:port/path?query)

Coroutine Instrumentation

Tracing\Aspect\CoroutineAspect - Coroutine Span Tracking

Tracing\Aspect\CoroutineAspect instruments coroutine creation to track async operations as separate spans in the trace tree. This aspect runs with the highest priority (PHP_INT_MAX) to ensure it intercepts coroutines before other aspects.

Coroutine Tracing Lifecycle


Sources: src/sentry/src/Tracing/Aspect/CoroutineAspect.php30-106

The aspect wraps the coroutine callable to:

  1. Restore context: Transfer context keys (like ServerRequestInterface) from parent coroutine src/sentry/src/Tracing/Aspect/CoroutineAspect.php69-71

  2. Start new transaction: Use continueTrace() with parent span's traceparent and baggage to maintain trace continuity src/sentry/src/Tracing/Aspect/CoroutineAspect.php74-80

  3. Create preparation span: Track coroutine setup overhead with coroutine.prepare operation src/sentry/src/Tracing/Aspect/CoroutineAspect.php77

  4. Create execution span: Track actual callable execution with coroutine.execute operation src/sentry/src/Tracing/Aspect/CoroutineAspect.php88-94

  5. Defer event flushing: Ensure events are sent when coroutine completes src/sentry/src/Tracing/Aspect/CoroutineAspect.php83-86

The CoroutineBacktraceHelper::foundCallingOnFunction() determines which function triggered the coroutine creation, used as the span description src/sentry/src/Tracing/Aspect/CoroutineAspect.php54-58

Annotation-Based Tracing

TraceAnnotationAspect - @Trace Annotation Support

TraceAnnotationAspect enables developers to explicitly instrument methods by applying the @Trace annotation. This provides a declarative way to add custom spans without writing instrumentation code.

Annotation Attributes


Sources: src/sentry/src/Tracing/Aspect/TraceAnnotationAspect.php26-72

The @Trace annotation accepts two optional parameters:

  • op: Operation type (defaults to "method")
  • description: Human-readable description (defaults to ClassName::methodName())

Example usage scenarios:


The aspect captures method arguments in the span data as annotation.arguments src/sentry/src/Tracing/Aspect/TraceAnnotationAspect.php44-52 If tracing_tags.annotation.result is enabled, the return value is also captured src/sentry/src/Tracing/Aspect/TraceAnnotationAspect.php56-60

Server Information Extraction Pattern

A common pattern across multiple aspects is the two-phase server information extraction:

Phase 1: Connection/Socket Creation

  • Intercept low-level connection/socket creation methods
  • Extract server host and port from connection parameters
  • Cache the information (often using WeakMap for automatic cleanup)

Phase 2: Operation Execution

  • Intercept high-level operation methods (query, request, etc.)
  • Retrieve cached server information
  • Store in SentryContext for the current coroutine
  • The EventHandleListener or aspect's trace() callback reads from SentryContext to populate span data

Server Information Storage


Sources: src/sentry/src/SentryContext.php26-145 src/sentry/src/Tracing/Aspect/DbConnectionAspect.php31-35 src/sentry/src/Tracing/Aspect/RedisConnectionAspect.php31-35

This pattern allows aspects to remain loosely coupled while ensuring that server information is available when creating spans. The SentryContext class provides dedicated getter/setter methods for each resource type:

ResourceContext KeysMethodsLine Reference
DatabaseCTX_DB_SERVER_ADDRESS, CTX_DB_SERVER_PORTsetDbServerAddress(), getDbServerAddress(), setDbServerPort(), getDbServerPort()src/sentry/src/SentryContext.php117-135
RedisCTX_REDIS_SERVER_ADDRESS, CTX_REDIS_SERVER_PORTsetRedisServerAddress(), getRedisServerAddress(), setRedisServerPort(), getRedisServerPort()src/sentry/src/SentryContext.php77-95
RPCCTX_RPC_SERVER_ADDRESS, CTX_RPC_SERVER_PORTsetRpcServerAddress(), getRpcServerAddress(), setRpcServerPort(), getRpcServerPort()src/sentry/src/SentryContext.php97-115
ElasticsearchCTX_ELASTICSEARCH_SPAN_DATAsetElasticsearchSpanData(), getElasticsearchSpanData()src/sentry/src/SentryContext.php137-145

The use of Hyperf's Context ensures that server information is coroutine-safe and automatically cleaned up when the coroutine completes, preventing information leakage between concurrent requests.

Configuration and Feature Flags

All aspects check feature flags before instrumenting operations. The Feature class provides centralized configuration checks:

  • Feature::isTracingSpanEnabled(string $key) - Checks if a specific span type is enabled and if a parent span exists
  • Feature::isTracingTagEnabled(string $key, bool $default) - Checks if specific data tags should be included in spans

Configuration is defined in src/sentry/publish/sentry.php147-171:


This granular control allows teams to disable expensive or sensitive instrumentation in production while keeping core tracing enabled.

Sources: src/sentry/src/Feature.php86-111 src/sentry/publish/sentry.php147-171

Refresh this wiki

On this page