×
Community Blog Kernel-Level X-Ray Vision: CloudMonitor 2.0 Achieves Full-Stack Observability with Zero Code Changes

Kernel-Level X-Ray Vision: CloudMonitor 2.0 Achieves Full-Stack Observability with Zero Code Changes

This article introduces how CloudMonitor 2.0 leverages OpenTelemetry eBPF Instrumentation (OBI) to achieve full-stack observability with zero code changes.

Background

In the cloud-native and microservices models, a production system often spans multiple language runtimes, such as Go, Java, Python, and Node.js. The deployment forms are scattered among containers, Kubernetes, and Serverless. To establish unified observability in such a heterogeneous environment, the traditional approach is to mount an intrusive Agent or SDK for each language. This involves modifying code, installing packages, aligning versions, and republishing. Each time a new service is connected, an engineering project is required. Under the fast research and development iteration pace, the cost of "connection means modification" is becoming increasingly unbearable.

At the same time, AI Agent applications are evolving from single Large Language Model (LLM) invocations to complex workflows with multi-step orchestration. A user request may trigger dozens of LLM invocations, Tool Calls, and AISearch. The invocation chain spans the Agent orchestration layer, LLM Provider, vector database, and external tools. Traditional application performance management (APM) is difficult to completely cover this. Zero-code observability solutions are equally indispensable in AI scenarios.

eBPF provides another idea. You can mount sandboxed probes in the Linux kernel to observe the network traffic, library function calling, and even system calls entering and leaving each process without modifying applications or restarting processes. Based on this capability, zero-code, cross-language, and low-overhead observability solutions are becoming a reality. OpenTelemetry eBPF Instrumentation (OBI) is the official answer provided by the OpenTelemetry community.

As an open source project officially maintained by OpenTelemetry, what OBI does can be summarized in one sentence. It utilizes the eBPF technology of the Linux kernel to automatically intercept and analyze network traffic and GPU operations entering and leaving the application without modifying any application code, and generates traces and metrics that comply with OpenTelemetry standards.

You can imagine it as a "X-ray glass" installed in the operating system kernel. Whether your application is written in Go, Java, Python, Node.js, or .NET, and regardless of what HTTP framework you use, what database you connect to, or which Large Language Model (LLM) you invoke, OBI can intercept communication at the kernel and library function layers, parse protocol semantics, and then output standard telemetry data. In terms of AI observability, OBI has built-in protocol-level tracking for four major GenAI Providers: OpenAI, Anthropic, Google Gemini, and Qwen. It can automatically detect LLM invocations and fetch Tool Call information from the response. It also supports the tracking of Rerank and AISearch operations, covering the core stages of the retrieval-augmented generation (RAG) pipeline.

It supports Linux amd64/arm64 architectures. The kernel requirement is 5.8+ (can be downgraded to 4.18+ for the RHEL series). The Deployment Method is flexible. You can run it as an independent process, deploy it as a Docker container, or deploy it as a Kubernetes DaemonSet.

1_

Three Pillars: Application Monitoring, Network Monitoring, and Log Enhancement

The core capabilities of OBI revolve around three observability pillars.

  • Application Observability: Distributed tracing (Traces) + RED Metrics. It covers more than 15 mainstream protocols and scenarios, such as Web, databases, message queues, GenAI, and GPU. It automatically injects trace_id and span_id into JSON logs to achieve Trace-Log association.
  • Network Observability: L3/L4 network traffic monitoring and TCP/UDP traffic statistics. It supports GeoIP, reverse DNS, CIDR annotation, TCP RTT measurement, TCP connection failure statistics, and edge zone-level global metrics.
  • Log Enhancement: Transparently inject trace_id and span_id into JSON logs in a language-independent manner to achieve Trace-Log association (for more information, see the "Log Enhancement" section below).

Protocol Panorama: From HTTP to CUDA, Catching Everything in One Net

The core competitiveness of OBI lies in protocol-aware probing. It not only records that "there is a network request", but also deeply understands the semantics of each request. The following is the complete protocol matrix currently supported.

Web and RPC

Protocol TLS Support Context propagation Remarks
HTTP 1.x Yes Yes Complete Request/response parsing
HTTP/2 Yes Go library level * Automatic parsing of frames and header compression
gRPC Yes Go library level * HTTP/2 frame-based method fetch
GraphQL Yes operation name and Type fetch
  • Cross-process context propagation for non-Go languages is uniformly implemented through the HPACK injection of the kernel mode tpinjector. For more information, see the "Cross-process Propagation" section.

Database

Protocol TLS Featured capabilities
MySQL Yes SQL query text capture
PostgreSQL Yes SQL query text capture
MSSQL Yes SQL query text capture
Redis Yes db.namespace property
MongoDB Yes CRUD Operation Type detection
Couchbase Yes SQL++ query capture
Memcached Yes ASCII text-based protocol
Elasticsearch / OpenSearch Yes search/bulk/doc operation

Message Queue

Protocol TLS Featured capabilities
Kafka Yes produce/fetch, topic fetch
MQTT 3.1.1 and 5.0, publish/subscribe
NATS PUB/HPUB and MSG/HMSG
AWS SQS Yes Complete message operation

How Protocols Are Detected

How does OBI determine whether a segment of Transmission Control Protocol (TCP) payload is MySQL or Redis without decryption or relying on port conventions? The core lies in ReadTCPRequestIntoSpan (pkg/ebpf/common/tcp_detect_transform.go), which is a three-level waterfall match. It attempts to match in the order of "certainty from high to low" sequentially, and returns immediately upon a hit:

  1. Kernel annotated (fastest): dispatchKernelAssignedProtocol, where the user mode directly switch event.ProtocolType. The kernel constants (common.go) are: MySQL=1, Postgres=2, Kafka=4, MQTT=5, MSSQL=6, NATS=7, AMQP=8. The SQL branch uses sentinel faults errFallback (fall back to the next level) or errIgnore (discard) for fine-grained control.
  2. Deterministic generic match: detectGenericProtocol, which sequentially tries matchSQL → matchFastCGI → matchMongo → matchCouchbase → matchMemcached. SQL will first try the Request buffer, then the response buffer (when the response is hit, it invokes reverseTCPEvent to correct the direction).
  3. Heuristic fallback (most prone to misjudgment, placed last): detectHeuristicProtocol, which tries matchRedis → matchMemcached → matchHTTP2 → matchNATS → matchAMQP → matchMQTT → matchKafkaFallback. The order itself is the accumulation of bug experience. For example, Hypertext Transfer Protocol 2 (HTTP/2) must be placed before Message Queuing Telemetry Transport (MQTT) because the heuristic of MQTT will falsely hit the connection preface of HTTP/2.

Several details to prevent misjudgment that are worth following:

  • SQL: First, it filters by printable American Standard Code for Information Interchange (ASCII) prefix (threshold = len("SELECT 1")), then searches for the keyword case-insensitively, and finally uses sqlprune.SQLParseOperationAndTable to fetch the operation and Table name. The validSQL requires "having an operation + (explicit Database (DB) Type or having a Table name)" to be counted.
  • Postgres: It validates the 5-byte message header, Type byte ∈ {Q,B,C}, and big-endian length in 0..3000. It also maintains the Least Recently Used (LRU) cache of the prepared statement and portal to revert the parameterized query.
  • HTTP/2 vs gRPC: First, isLikelyHTTP2 performs Request for Comments (RFC) 7540 frame-by-frame rationality validation (the upper limit of frame length is set to 1<<22, approximately 4 MB, as the validation tolerance value. Note that the RFC 7540 default frame size is 2^14, which is 16 KB. It uses the flags mask). Then, it differentiates them by looking at the content-type: application/grpc or grpc-status header.

Each protocol has a corresponding TCPToToSpan constructor to form a request.Span.

Language depth Integration: Not limited to the Network Layer

The detection of OBI is divided into two layers. The first layer is language-independent network-level tracing—applications of any language can obtain basic traces and metrics through TCP traffic blocking. The second layer is runtime-specific depth Integration—for specific languages and frames, OBI directly hooks library functions through uprobe to achieve more precise context propagation and trace association.

runtime Integration method depth capabilities
Go 1.17+ uprobe directly hooks 13+ libraries net/http, gin, gorilla/mux, gRPC, kafka-go, sarama, go-redis, MongoDB, database/sql, etc. Kernel reconstruction of goroutine parent-child relationship
Java 8+ uprobe hooks OpenSSL / JVM key functions TLS encrypted traffic plaintext tracking. Cross-process context goes through kernel tpinjector
Node.js 8+ async_hooks uprobe In-process asynchronous context propagation
.NET 6+ OpenSSL uprobe + Network-level kprobe TLS encrypted traffic plaintext tracking (protocol detection and cross-process propagation reuse the general Network Layer)
Python 3.9+ asyncio / uvloop uprobe coroutine context propagation
Ruby 3.0+ Puma uprobe rb_ary_shift work queue tracking
Nginx Dedicated uprobe HTTP server Request border detection
All languages Network-level kprobe TCP/HTTP automatic detection (language-independent baseline capability)

Go does not have ThreadLocal. How does OBI string together an invoke?

The goroutine of Go drifts among operating system (OS) threads. The thread local storage of traditional application performance management (APM) completely fails. The solution of OBI is to rebuild the parent-child relationship of goroutines in the kernel (bpf/gotracer/go_runtime.c + go_common.h). The solution hooks runtime.newproc1 to record which goroutine creates which goroutine and writes the record into the least recently used (LRU) ongoing_goroutines. When an outbound invocation needs to find the inbound request to which the outbound invocation belongs, find_parent_goroutine traces back up to 6 layers upwards along the parent chain. The deep nest is to be compatible with Kafka clients such as franz-go. Then, the solution hooks runtime.casgstatus to trail the status switch and attach the OBI context to the goroutine. This allows the kernel probe (kprobe) on the same OS thread to associate correctly.

The asyncio of Python uses single-threaded multiplexing. How does OBI distinguish concurrent requests?

The asyncio event loop of Python alternately executes hundreds or thousands of coroutines (Tasks) on the same OS thread. The traditional assumption of "one thread corresponds to one request" completely fails. What is more troublesome is that asyncio.to_thread() delivers the work to the thread pool. These worker threads do not have the asyncio.Task identity at all. The solution of OBI is to track the Task and Context objects of CPython in the kernel and rebuild the parent-child relationship of the coroutines.

The core consists of four groups of user-space probes (uprobes) (bpf/generictracer/python.c). The task_step tracks which Task the event loop switches to. The _asyncio_Task___init__ records the parent-child relationship and inherits the request connection when the Task is created. The PyContext_CopyCurrent attaches the replica to the corresponding Task when the Context is copied. Both create_task and to_thread trigger this action. The context_run recovers the Task identity when the worker thread activates the Context. Three Berkeley Packet Filter (BPF) Maps (python_thread_state / python_task_state / python_context_task) work together to cover four concurrent modes: await, create_task, gather, and to_thread.

The parent chain traceback mechanism (find_python_owning_server_trace) is similar to Go. The mechanism traces upwards along the parent pointer from the current Task for up to 4 layers until the mechanism finds the ancestor Task that holds the inbound request connection (server_traces_aux). Then, the mechanism can associate with the correct server span. The problem of Task address reuse is solved by the version counter. Each time the Task is initialized, the version auto increments. The version is snapshotted when the Context is attached. If the comparison is inconsistent during the search, the Task is determined to expire.

The entire solution is anchored on the CPython _asyncio and libpython symbols, and does not depend on the internal implementation of uvloop. The uvloop only replaces the I/O driver of the event loop. The semantics of asyncio.Task and contextvars remains unchanged. Therefore, the same group of probes is effective for both asyncio and uvloop, and no additional adaptation is required.

Cross-process propagation is uniformly completed in the kernel mode for non-Go languages.

The language runtime table in the previous text easily gives the impression that the cross-process context propagation is implemented by the language runtime of each language respectively. A more accurate expression is that the in-process context propagation is indeed exclusive to each language (Go goroutine traceback, Node async_hooks, Python asyncio, Ruby Puma queue, and Java/.NET tracking via OpenSSL/Java Virtual Machine (JVM) uprobe). However, the cross-process traceparent propagation is uniformly completed in the kernel mode by tpinjector for all non-Go languages (pkg/internal/ebpf/tpinjector + bpf/tpinjector/*.c). There are three methods:

  • HTTP/1 header injection: The sk_msg program rewrites the payload via the tail call chain and inserts the Traceparent: header. The SSL socket is directly skipped (the ciphertext cannot be modified).
  • HTTP/2 HPACK injection: Inject the HPACK-encoded traceparent per stream, and use the huffman fingerprint 0x3fa9851d6b21834d to detect existing headers.
  • TCP Option propagation (Custom TCP options): The options kind is 25. For outbound traffic, bpf_store_hdr_opt writes trace_id/span_id in the WRITE_HDR_OPT callback. For inbound traffic, bpf_load_hdr_opt retrieves the trace_id/span_id in PARSE_ALL_HDR_OPT, and writes the trace_id/span_id into incoming_trace_map (using the normalization connection_info_t as the key) for Consumption by the server-side server_trace_parent before the trace_id/span_id is deleted. During startup, sock_iter.c also fills established persistent connections into sockhash, so that old connections can also be injected.

Deployment notes: TCP Option kind=25 belongs to an unassigned IANA number. Some firewalls, Server Load Balancers, and cloud platform middleboxes may strip unknown TCP options, which causes the propagation to fail in silence. We recommend that you verify the pass-through capability of TCP options in the target network environment, or prioritize the use of the HTTP header injection method (OTEL_EBPF_BPF_CONTEXT_PROPAGATION=headers).

This is controlled by OTEL_EBPF_BPF_CONTEXT_PROPAGATION: headers/tcp/all/disabled. finder.go determines whether to load the injector based on this configuration.

The Complete Lifecycle of a Span (Data Pipeline and Architecture)

How does a byte stream captured in the kernel become that trace in CloudMonitor 2.0? This is exactly the most hardcore engineering part of OBI. The user mode of OBI is not a large loop. Instead, the user mode is an explicitly declared, phased, and pluggable directed graph (DAG).

2

Top-level Skeleton: Three Independent Agents + errgroup

The entry point RunWithContextInfo (pkg/instrumenter/instrumenter.go) splits the three main pillars into three independent goroutines based on Feature Flags, and uses errgroup to attach them. If any goroutine crashes, the other two goroutines undergo a graceful shutdown when the context is canceled. The application observability pipeline is divided into three steps (pkg/internal/appolly/appolly.go): FindAndInstrument (Search and attach probes) → ReadAndForward (Start the processing pipeline) → WaitUntilFinished.

Pipeline Orchestration Framework: swarm (two-stage Start)

OBI has developed a minimalist node orchestration framework pkg/pipe/swarm. The core of the framework is the two-stage semantics of "instantiate all first, and then Run uniformly".

In the first stage, Instancer.Instance(ctx) invokes the InstanceFunc of each node in sequence. If an initialization failed error occurs, the framework immediately cancels the process and returns an error as a whole. No RunFunc will Start, which avoids the incomplete Status of a "half-Start". In the second stage, Runner.Start(ctx) spawns a goroutine for each node, which can be configured with WithCancelTimeout. After the context is canceled, if a node fails to exit within the timeout, Done() returns CancelTimeoutError and identifies the specific zombie node.

Inter-node communication: msg.Queue (fan-out queue with deadlock detection)

Nodes do not invoke each other directly. Instead, nodes pass messages through the generic queue msg.Queue[T] (pkg/pipe/msg/queue.go):

  • fan-out: A queue can be Subscribed by multiple downstream nodes. SendCtx delivers the same message to all subscribers. When no subscriber exists, the message is directly discarded and does not block the sender.
  • Bypass (zero-cost short circuit): When a branch is configured for shutdown, input.Bypass(output) directly transfers the upstream subscribers to the downstream nodes. The disabled node does not perform a dry-run, but physically disappears from the graph.
  • Deadlock self-check: SendCtx has a built-in sendTimeout timer (default 1 minute). An alerting is triggered if a channel write block of a subscriber times out. In PanicOnSendTimeout pattern, it directly panics and prints the A->B->C path.
  • Multiple producers shutdown: ClosingAttempts(n) + MarkCloseable() reference counting. It truly closes only after all producers are marked as closeable.

Complete Directed Acyclic Graph (DAG) for Application Observability

The Build() function in pkg/internal/appolly/instrumenter.go explicitly pieces together the entire graph:

[per-process eBPF tracers]
   | (processes share the Ring Buffer)
   v
   ringBufForwarder  (reader goroutine + parser goroutine, object pool 2 × BatchLength)
   | tracesInput  (batch=100 / 1 s / 3 s idle-flush)
   v
ReadFromChannel -> Routes -> KubeDecorator -> DockerDecorator -> NameResolution -> AttributesFilter
   |
   v  exportableSpans  ===== fan-out =====
   |-- OTEL Traces Exporter
   |-- Printer (debug)
   |-- SpanNameLimiter -> [OTEL Metrics | SvcGraph Metrics | Prometheus]
   `-- BPF Metrics

Two engineering design points: (1) The Metric sub-pipeline is started on demand. The setupMetricsSubPipeline is executed only if a Metric export is actually configured. (2) Special timeout for K8s decorators. The routerToKubeDecorator queue takes max(InformersSyncTimeout, ChannelSendTimeout) because the full informer snapshot must be pulled first during startup, and it cannot be mistakenly killed by the default deadlock detection.

Transport from kernel to user mode: ringbuf forwarder with dual goroutines and an object pool.

This is the ingest endpoint of the entire pipeline, and also the most Performance-sensitive place (pkg/ebpf/common/ringbuf.go, generic ringBufForwarder[T], where T=Span on the application side and T=Record on the Stats side reuse the same Code):

  • Read/parse separated producer-consumer: The readerLoop is only responsible for ReadInto the original record, and the parserLoop is responsible for parsing it into a Span. They pass the slot indices through two channels: freeIdx and workIdx.
  • Object pool avoids Garbage Collection jitter: Pre-assign poolSize = 2 * BatchLength records for reuse (one batch is for the parser, and one batch is for concurrent padding by the reader).
  • Batch commit + timeout fallback: It flushes when BatchLength (default 100) is reached. If it is not reached, the BatchTimeout (default 1 s) ticker acts as a fallback. In addition, flushOnAvailableBytes actively flushes by checking the residual bytes of the ringbuf every 3 s to prevent Data from being stuck in the kernel under low traffic.
  • Shared ringbuf: Hundreds or thousands of probed processes share a SharedRingBuffer, and thousands of closers execute concurrent Close() upon exit.

When any internal queue is blocked, OBI proactively prompts the full set of tuning knobs: OTEL_EBPF_OTLP_TRACES_BATCH_MAX_SIZE, OTEL_EBPF_OTLP_TRACES_QUEUE_SIZE, OTEL_EBPF_CHANNEL_BUFFER_LEN, OTEL_EBPF_CHANNEL_SEND_TIMEOUT, OTEL_EBPF_BPF_BATCH_LENGTH, and OTEL_EBPF_BPF_BATCH_TIMEOUT.

One-sentence summary: OBI = a swarm-orchestrated DAG + a set of fan-out queues with deadlock Detection + a dual-goroutine object pool ringbuf forwarder. The Start is either fully Succeeded or fully rolled back. The shutdown can locate zombie nodes. The disabled features physically disappear from the graph.

GPU/CUDA Tracking: Covering Kernel Launches and VARM Operations

In addition to depth probing at the network protocol layer, OBI extends observability to the GPU Compute realm. By hooking libcuda.so via uprobes, it can track the core operations of NVIDIA CUDA: kernel launches, graph launches, memory assignments, and memory copies. This is highly valuable for GPU clusters running AI training and infer Jobs.

CUDA operation Tracking Data Prometheus Metric
cudaLaunchKernel grid dimension, block dimension cuda_kernel_launch_calls_total, cuda_kernel_grid_size / block_size
cudaGraphLaunch graph Start event cuda_graph_launch_calls_total
cudaMalloc Allocated memory size cuda_memory_allocations_total
cudaMemcpyAsync Copy size and direction cuda_memory_copy_size

The configuration of GPU tracking is very simple: OTEL_EBPF_CUDA_MODE=auto automatically detects whether the System has CUDA libraries and enables tracking.

GPU tracking uses uprobes to hook libcuda.so combined with an independent ring buffer (bpf/gpuevent on the kernel side, and pkg/internal/ebpf/gpuevent in user mode). An engineering detail worth pointing out is that CUDA events enter the processing pipeline through the same generic forwarder ringBufForwarder[T] (pkg/ebpf/common/ringbuf.go) as Network Spans. Therefore, CUDA events naturally share the same batch commit, backpressure control, and graceful shutdown mechanisms, eliminating the need to maintain separate transport logic for the GPU. This also explains why OTEL_EBPF_CUDA_MODE=auto can achieve zero-extra-configuration integration: it essentially just attaches an additional data source to the existing processing DAG.

Network Layer Observation: Traffic, Association, and Quality

In addition to application-level distributed tracking, OBI also provides Network-level observability.

Network Traffic Monitor (NetO11y)

Based on TC hooks, OBI catches L3/L4 network packets, parses IPv4/IPv6 and TCP/UDP headers, and generates network traffic Metrics. The Data pipeline supports rich decoration capabilities: Kubernetes metadata, reverse DNS, GeoIP geolocation, and Custom CIDR range annotation. This is suitable for intra-cluster and inter-cluster traffic Analysis, network topology visualization, and security audits.

Typical Troubleshooting Scenarios

  • Suspicious Outbound Connections Discovery (security audit): An unknown IP address suddenly appears in the service topology with a large amount of data transmission (such as 2.3 GB/h) to the database. By combining rDNS reverse lookup and GeoIP geolocation, you discover that the Target is overseas. This immediately triggers a security alert.
  • Cross-zone traffic spike troubleshooting: Cross-zone traffic suddenly doubles during a certain period. After aggregating by CIDR annotation, you discover that a routing configuration Change for a certain service causes all Requests to detour to another AZ. After the issue is fixed, bandwidth costs drop back to normal.
  • service Dependency discovery: Without any configuration, OBI automatically generates a cluster-wide inter-service traffic topology. When a service is abnormal, you can immediately see all of its upstream and downstream Network relationships and traffic changes.

3

Statistical Metrics (StatsO11y)

By using kprobes or tracepoints, OBI collects node-level TCP RTT (obi_stat_tcp_rtt_seconds) and the Count of failed TCP connections (obi_stat_tcp_failed_connections) to help you monitor the underlying network quality.

Typical Troubleshooting Scenarios

  • Fast network congestion delimitation: The response of a service slows down, and the Transmission Control Protocol (TCP) round-trip time (RTT) surges from 2 ms to 180 ms. You do not need to troubleshoot layer by layer. You can directly view the RTT Metric and perform aggregation by Target IP address. Within 1 minute, you can localize the congestion to the vSwitch where the payment-gateway edge zone is located.
  • vSwitch/CIDR block fault localization: The number of failed TCP connections suddenly erupts in the 10.0.2.0/24 CIDR block, while other CIDR blocks are Normal. You can immediately infer that the vSwitch or Ingress of this CIDR block has issues, and notify the Network team to intervene.

4

Log Enrichment: Kernel Block + Transparent Injection of trace_id

The log enrichment of OBI is a language-independent capability. Regardless of what language or log frame the application uses, as long as it writes logs in JavaScript Object Notation (JSON) format to stdout/stderr or pipe, OBI can block them at the kernel layer and transparently inject trace_id and span_id. With zero modifications to the application Code, the Trace foreign key field automatically appears in the log file.

Implementation principle (bpf/logenricher/logenricher.c): Hook the tty_write (terminal Outputs) and pipe_write (pipe Outputs, covering the docker logs/kubectl logs scenarios) kernel functions via kprobe. When the write operation of the monitored process is triggered, the Berkeley Packet Filter (BPF) program reads the raw log Content (maximum 8 KB) from the user mode buffer. At the same time, it retrieves the trace context of the current thread or coroutine via obi_ctx, then uses bpf_probe_write_user to erase the raw log (padding with zero bytes), and sends the event via ringbuf to the user mode.

Known limitations: bpf_probe_write_user directly modifies the user mode memory, and there are two threats to follow: (1) A time window exists between the kernel zero-erasing and the user mode write-back. If the process crashes or the log collector happens to read the Outputs during this period, log loss or blank lines may occur. (2) Some security hardening kernels (such as those with the Lockdown pattern enabled) disable this function. Before deployment, you must confirm that the kernel configuration allows this operation.

After the user mode processor (pkg/internal/ebpf/logenricher) accepts the event: It attempts to parse the log line into JSON. If it is Succeeded, it injects the trace_id and span_id fields into the object (if they already exist, it does not overwrite them), and after it serializes them, it writes them back to the raw Outputs path of the application (TTY pts or pipe fd). If it is not JSON, it writes the log line back as is. The write-back path is parsed via path_resolver from the kernel file->f_path (TTY scenario) or located from /proc//fd/ (pipe scenario), and a Least Recently Used (LRU) cache is used to avoid repeated open operations.

Several engineering highlights: On the kernel side, the current fd is pre-recorded via ksys_write/do_writev kprobe, and when pipe_write is triggered, the file descriptor (fd) can be associated with the correct pipe. The asynchronous writer (ShardedQueue) performs shards by File Path, and the writing of the same file is Strict serial to guarantee the log line sequence. If the application already comes with the OpenTelemetry (OTel) software development kit (SDK) to export Traces (ExportsOTelTraces), only trace_id is injected, but not span_id, to avoid conflicts with the span of the application itself.

Use OBI (OpenTelemetry Non-intrusive Monitoring) in CloudMonitor 2.0

One-click Integration

Via the Integration Center of CloudMonitor 2.0, select OpenTelemetry Non-intrusive Monitoring, and select one-click integration for the cluster [1].

5

Application Details

After integration, you can view the number of Requests, Number Of Error, and Duration of the application, as well as the invoke details of the API.

6

Trace Analysis

In Trace Analysis, you can view the complete Trace link, making issues clear at a glance.

7

Network Monitoring

Taking the "source service → Target service" link as the core perspective, it displays the network traffic rate and TCP round-trip time (P50/P95/P99) between microservices in the Kubernetes (K8s) cluster in real-time. It is used for network quality inspection, delay abnormal localization, and traffic Distribution Analysis.

8

To better use the capabilities of OBI, you can achieve one-click integration via the Integration Center of CloudMonitor 2.0. Next, we will gradually supplement Artificial Intelligence (AI) Agent observability capabilities [2] and more Network Monitoring capabilities into OBI. You are welcome to build together.

[1] CloudMonitor 2.0 Integration Center: https://www.alibabacloud.com/help/cms/cloudmonitor-2-0/kan

[2] https://github.com/open-telemetry/opentelemetry-ebpf-instrumentation/issues/1854

0 1 0
Share on

You may also like

Comments

Related Products