【问题标题】:Using OTEL Java agent, how to create a new Context without using @WithSpan使用 OTEL Java 代理,如何在不使用 @WithSpan 的情况下创建新的上下文
【发布时间】:2021-03-22 18:05:32
【问题描述】:

opentelemetry-javaagent-all 代理(版本 0.17.0 和 1.0.1)是向我的 Java 应用程序添加跟踪信息的起点。自动仪表效果很好。

我的某些应用程序无法自动检测。对于应用程序的这一部分,我首先将@WithSpan 注释添加到代码中有趣的地方。

我现在通过简单的@WithSpan 注释达到了看似可行的极限。但是,我的应用程序底层的框架允许我注册要在某些点调用的回调——例如我可以提供在客户端连接/断开连接时收到通知的处理程序。

我认为我需要的是在调用 Foo.onConnect() 时启动一个新的 Span,并将其设置为与每个请求对应的 Spans 的父级。

public class Foo {

    void onConnect() {
        // called when a client connects to my app
        // Here I want to create a Span that will be the parent of the Span created in
        // Foo.processEachRequest().
    }

    @WithSpan
    public void processEachRequest() {
        // works, but since it is called for each request... each span is in a separate Trace
    }

    void onDisconnect() {
        // called when the client disconnects from my app
        // Here I can end the parent Span.
    }
}

其他想法 - 没有成功:

1 - 显而易见的解决方案是将@WithSpan 注释添加到底层框架。由于各种原因,这不会是一个切实可行的前进方向。

2 - 下一个选择可能是寻找一种方法来告诉 javaagent 我的底层框架中的方法。 (New Relic 代理可以做这样的事情。)无论如何,这似乎不是开放遥测代理的一个特性。

所以,我只剩下寻找一种使用回调的方法来做到这一点,如上所述。 有没有办法做到这一点?

【问题讨论】:

  • 如果您需要在onConnect 上的跨度,为什么不用@WithSpan 注释onConnect 方法?
  • 注释只会在 onConnect 方法的持续时间内创建一个 Span。(当 onConnect 返回时 Span 将结束。)
  • 还有一个问题:客户端一般连接多久?您通常希望避免创建开放几分钟或几小时的跨度。 processEachRequest()方法中如何识别客户端?

标签: java open-telemetry


【解决方案1】:

这应该可以通过手动检测您的代码来实现。您将使用 OpenTelemetry 的Tracer 接口,如OpenTelemetry Java docs 中所述。

这应该给你一个大致的想法:

public class Foo {
    private Span parentSpan; // you might need a Map/List/Stack here

    void onConnect() {
        Tracer tracer =
                openTelemetry.getTracer("instrumentation-library-name", "1.0.0");
        Span span = tracer.spanBuilder("my span").startSpan();
        this.parentSpan = span; // might need to store span per request/client/connection-id
    }

    public void processEachRequest() {
        final Span parent = this.lookupParentSpan();
        if (parent != null) {
            try (Scope scope = span.makeCurrent()) {
              yourLogic();
            } catch (Throwable t) {
              span.setStatus(StatusCode.ERROR, "error message");
              throw t;
            }
        } else {
            yourLogic();
        }
    }

    void onDisconnect() {
        final Span parent = this.lookupParentSpan();
        if (parent != null) {
            parent.end();
        }
    }

    private Span lookupParentSpan() {
        // you probably want to lookup the span by client or connection id from a (weak) map
        return this.parentSpan;
    }
}

注意:您必须保证跨度始终结束并且不会泄漏。确保正确确定范围并最终调用 Span#end()

【讨论】:

    猜你喜欢
    • 2010-11-22
    • 1970-01-01
    • 2019-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-06
    • 2014-07-25
    相关资源
    最近更新 更多