@@ -245,6 +245,179 @@ classDiagram
245245 SeriesResult "1" *-- "0..*" Series: contains
246246```
247247
248+ # OpenTelemetry integration design
249+ To enhance the observability of the OpenGemini client and facilitate tracking of performance metrics, errors, and other information related to query and write operations, this solution adopts the interceptor pattern to integrate OpenTelemetry, enabling full-link tracing. The design supports non-intrusive extensions, allowing coexistence with other interceptors (such as logging and authentication interceptors) while minimizing modifications to the original client.
250+
251+ ## Interceptor design
252+ The interceptor pattern defines a standardized interface to hook into client operations (query/write) and inject telemetry logic.
253+
254+
255+ ``` mermaid
256+ Interceptor interface {
257+ Query(ctx context.Context, query *InterceptorQuery) InterceptorClosure
258+ Write(ctx context.Context, write *InterceptorWrite) InterceptorClosure
259+ }
260+ ```
261+
262+ ## Define the base client class,associated with the Interceptor interface
263+ The base Client class manages a collection of interceptors, allowing dynamic registration and execution of interceptor logic during client operations.
264+
265+ ``` mermaid
266+ class Client {
267+ - []Interceptor interceptors
268+ }
269+ ```
270+
271+ ## Define the interceptor implementation class integrating OpenTelemetry,implementing the Interceptor interface
272+ The OtelClient class implements the Interceptor interface, embedding OpenTelemetry logic to capture traces, metrics, and logs for client operations.
273+
274+ ``` mermaid
275+ class OtelClient {
276+ Interceptor
277+ }
278+ ```
279+
280+ ## Tracing system core module
281+
282+ ``` mermaid
283+ class TraceContext {
284+ + traceId: String
285+ + parentTraceId: String
286+ + operationName: String
287+ + timestamp: Long
288+ + attributes: Map~String, Object~
289+ + createChildContext() : TraceContext
290+ + addAttribute(key, value) : void
291+ + getAttribute(key) : Object
292+ }
293+
294+ class ContextManager {
295+ + getCurrentContext() : TraceContext
296+ + bindContext(context, task) : void
297+ + unbindContext() : TraceContext
298+ }
299+
300+ class OperationInterceptor {
301+ <<Interface>>
302+ + preProcess(operationContext) : void
303+ + postProcess(operationContext, result) : void
304+ + errorProcess(operationContext, exception) : void
305+ }
306+
307+ class QueryInterceptor {
308+ + preProcess(operationContext) : void
309+ + postProcess(operationContext, queryResult) : void
310+ + errorProcess(operationContext, exception) : void
311+ }
312+
313+ class WriteInterceptor {
314+ + preProcess(operationContext) : void
315+ + postProcess(operationContext, writeResult) : void
316+ + errorProcess(operationContext, exception) : void
317+ }
318+
319+ class InterceptorChain {
320+ + interceptors: List~OperationInterceptor~
321+ + addInterceptor(interceptor) : void
322+ + executePreFlow(operationContext) : void
323+ + executePostFlow(operationContext, result) : void
324+ + executeErrorFlow(operationContext, exception) : void
325+ }
326+
327+ class OperationContext {
328+ + traceContext: TraceContext
329+ + operationType: Enum~Query/Write~
330+ + operationParams: Map~String, Object~
331+ + getTraceContext() : TraceContext
332+ + setOperationResult(result) : void
333+ }
334+
335+ class SDKConfigurator {
336+ + configureExporter(exporter) : SDKConfigurator
337+ + configurePropagator(propagator) : SDKConfigurator
338+ + configureTracerProvider(provider) : SDKConfigurator
339+ + initialize() : OpenTelemetrySDK
340+ }
341+
342+ class TraceExporter {
343+ <<Interface>>
344+ + exportTraceData(traceDataList) : void
345+ }
346+
347+ class ContextPropagator {
348+ <<Interface>>
349+ + inject(traceContext, carrier) : void
350+ + extract(carrier) : TraceContext
351+ }
352+
353+ class TracerProvider {
354+ + getTracer(name) : Tracer
355+ }
356+
357+ class Tracer {
358+ + createTraceContext(operationName) : TraceContext
359+ + endTraceContext(traceContext) : void
360+ }
361+
362+ class OpenTelemetrySDK {
363+ + getTracerProvider() : TracerProvider
364+ + getContextPropagator() : ContextPropagator
365+ + getTraceExporter() : TraceExporter
366+ }
367+
368+ QueryInterceptor ..|> OperationInterceptor
369+ WriteInterceptor ..|> OperationInterceptor
370+ InterceptorChain o-- OperationInterceptor : contains
371+ OperationContext o-- TraceContext : holds
372+ ContextManager o-- TraceContext : manages
373+
374+ SDKConfigurator ..> TraceExporter : configures
375+ SDKConfigurator ..> ContextPropagator : configures
376+ SDKConfigurator ..> TracerProvider : configures
377+ SDKConfigurator ..> OpenTelemetrySDK : initializes
378+ OpenTelemetrySDK o-- TracerProvider : contains
379+ OpenTelemetrySDK o-- ContextPropagator : contains
380+ OpenTelemetrySDK o-- TraceExporter : contains
381+ TracerProvider o-- Tracer : provides
382+ Tracer ..> TraceContext : creates/ends
383+
384+ InterceptorChain ..> OperationContext : processes
385+ Tracer ..> ContextManager : binds context
386+ ```
387+
388+ ## Usage Example(Go language examples)
389+
390+ ``` mermaid
391+ func main() {
392+ var ctx = context.Background()
393+ shutdown, err := setupOtelSDK(ctx)
394+ if err != nil {
395+ return
396+ }
397+ defer func() {
398+ err = errors.Join(err, shutdown(ctx))
399+ }()
400+
401+ config := &opengemini.Config{
402+ Addresses: []opengemini.Address{{
403+ Host: "127.0.0.1",
404+ Port: 8086,
405+ }},
406+ }
407+ client, err := opengemini.NewClient(config)
408+ if err != nil {
409+ fmt.Println(err)
410+ return
411+ }
412+
413+ client.Interceptors(opengemini.NewOtelInterceptor())
414+
415+ err = client.CreateDatabase("db0")
416+ if err != nil {
417+ }
418+ }
419+ ```
420+
248421# QueryBuilder design
249422
250423``` mermaid
0 commit comments