Skip to content

Latest commit

 

History

History
144 lines (111 loc) · 6.71 KB

File metadata and controls

144 lines (111 loc) · 6.71 KB

obs-sdk-java

opensourceways 微服务可观测薄封装 SDK 的 Java 实现,契约见根目录 spec/。 语义与 Go / Python / Node SDK 对齐:

  • community 双层注入service/env/instance 为部署级 const label,community 建模为普通可变 label, 值取请求上下文覆盖(可信判定点写入),未覆盖回退部署默认 —— 「注册一次两用」。
  • trace_id / span_id 预留:首期只保证字段可写可透传,不落 span。
  • 日志:结构化 JSON(logback + logstash JSON encoder,MDC 输出固定键)。
  • 指标:Micrometer + Prometheus registry 薄封装(业务 counter/gauge/histogram); HTTP 服务端指标不重复造轮子,Java 服务走 Spring Boot Actuator + Micrometer 官方 server instrumentation。

模块

组件 说明
context.RequestContext 请求级上下文(community/request_id/trace_id/span_id),ThreadLocal 作用域句柄,对齐其它语言的 sdkctx/contextvars/ALS
log.ObsLogging 部署默认字段 + 请求覆盖字段写入 SLF4J MDC
log.ObsJsonProvider logstash-logback-encoder 的 provider:按契约输出固定字段(时间/级别/字段名/顺序/异常堆栈)
ObsMetrics 业务指标装配(common tags + community 动态 label + namespace 前缀)
middleware.ObsFilter 可选 Servlet Filter:注入 request_id + 可信判定点解析 community → RequestContext + MDC

构建与测试

JDK 17 + Maven:

mvn test

当前开发机无 JDK/Maven,Java 代码未在本机编译运行;已按 Micrometer 1.13 公开 API 编写, 由仓库 CI(.github/workflows/ci.yml 的 java job)负责编译 + 跑 mvn test 验证。 如 CI 暴露问题,以 CI 输出为准修复。

指标使用

ObsSdkConfig cfg = ObsSdkConfig.builder()
        .service("review")          // 生产走 OBS_SERVICE 等环境变量,ObsSdkConfig.fromEnvironment()
        .env("test")
        .instance("pod-1")
        .community("openeuler")     // 部署级默认 community
        .build();
ObsMetrics m = ObsMetrics.of(cfg);

// 业务 counter —— community 自动排首位,值取请求上下文覆盖,否则回退默认
ObsMetrics.CounterVec built = m.counter("built_releases", "发布的构建数", "kind");
built.inc(1, "tag");

// 请求上下文内再埋 → 该条 series 的 community 被覆盖为 mindspore
try (RequestContext.Scope scope = RequestContext.push("mindspore", "req-1", null)) {
    built.inc(1, "tag");
}

// gauge / histogram(Timer 自动产出 _seconds_count/_sum,可配桶)
m.gauge("in_flight", "在飞请求数").set(3);
m.histogram("review_duration", "评审耗时", new double[]{0.1, 0.5}).observe(0.05);

// Prometheus text 快照(供自检 / 测试)
String text = m.text();

命名说明:Micrometer 会自动为 Counter 追加 _total、为 Timer(秒基)追加 _seconds, 因此 Java 侧传基础名(不带 _total/_seconds 后缀),导出名与其它语言 SDK 一致 (如 built_releases_totalreview_duration_seconds_count)。 跨服务共享 SDK 时给 namespace(如 "obs"),导出名变为 obs_<metric>_total

community 双层注入的日志侧

// 服务启动:
ObsLogging.init(ObsSdkConfig.fromEnvironment());

// 请求处理:先 init() 后每次请求在可信判定点解析后 push 即可
RequestContext.push(community, requestId, traceId);   // try-with-resource 作用域

集成:Spring Boot Actuator + Micrometer

Java 服务的服务端指标交给 Actuator 暴露(stater 对齐,SDK 不重复埋 HTTP 指标):

  1. 依赖 micrometer-registry-prometheus + 引入 spring-boot-starter-actuator
  2. 把 SDK 的 registry 暴露成 bean 让 Actuator 托管(PrometheusMeterRegistry 会被 actuator 自动发现并挂到 /actuator/prometheus):
@Bean
public PrometheusMeterRegistry prometheusRegistry(ObsSdkConfig obsConfig) {
    return ObsMetrics.of(obsConfig).meterRegistry();
}
  1. application.ymlmanagement.endpoints.web.exposure.include: prometheus

在接入服务里把 SDK 的 business 指标注册到同一个 PrometheusMeterRegistry(上面 bean 的实例), 即可与 Actuator 的服务端指标合并暴露给 AOM 抓取。

请求上下文中间件(可选 Servlet Filter)

// Spring Boot 注册,community resolver 必须来自可信判定点(路由前缀/认证主体/白名单),
// 不能裸读 URL/Header 当 community(见 spec/community-values.md)
@Bean
public FilterRegistrationBean<ObsFilter> obsFilter() {
    FilterRegistrationBean<ObsFilter> reg = new FilterRegistrationBean<>();
    reg.setFilter(new ObsFilter(req ->
            req.getRequestURI().startsWith("/mindspore") ? "mindspore" : null));
    reg.addUrlPatterns("/*");
    reg.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return reg;
}

日志 JSON 输出

examples/logback-json.xml 拷成接入服务的 logback 配置并引入 logstash-logback-encoder, 日志即输出单行 JSON,例:

{"time":"2026-09-10T08:13:42.725Z","level":"info","msg":"job done","service":"review","env":"test","instance":"pod-1","community":"openEuler","request_id":"req-1","logger":"ReviewSvc.java:51"}

固定字段的顺序、取值与缺失规则均由 SDK 的 ObsJsonProvider 保证,接入方无需(也无法)逐项配置:

字段 说明
time 固定毫秒精度 UTC,以 Z 结尾(不受 JVM 时区影响)
level 小写 debug / info / warn / errorTRACE 归入 debug
msg 格式化后的消息
service / env / instance / community 来自 MDC(ObsLogging.init 登记,community 可被请求上下文覆盖)
request_id / trace_id / span_id 请求级,来自 MDC;空值省略(后两者为二期预留)
logger 调用位置 文件:行号(对齐 Go 侧语义)
error 异常完整堆栈,仅在有 throwable 时出现

为什么不用 encoder 自带的 provider<logLevel/> 只能输出大写 INFO(7.4 无配置项可改 大小写,<logLevelValue/> 输出的是数字),字段名走 LogstashFieldNamesLoggingEventCompositeJsonEncoder 没有 setFieldNames,且不配 <stackTrace/>throwable 会被整条丢弃。故固定字段这一层由 SDK 自己的 provider 承担。

业务字段不属于固定字段,可在 ObsJsonProvider 之后追加 <mdc> / <keyValuePairs/> 等 provider,输出会落在固定字段之后。

依赖:logstash-logback-encoderjackson-core 在本 SDK 中为 provided scope (ObsJsonProvider 需要它们编译),运行时由接入服务提供,不随 SDK 传递。