stellspec-java-sdk 是 stellspec · 星谱 面向 Java 生态的日志 SDK。它基于 OpenTelemetry Logs,对自研框架暴露一组不依赖 Spring 的通用接入能力:
- 开发环境默认输出到
stdout/stderr - 非开发环境默认通过 OTLP 将日志发送到本机
log-agent - 统一映射
service.*、k8s.*、host.*等资源语义 - 支持 exporter 重试、最终失败本地落盘、超长正文截断
- 支持结构化错误属性
error.type、stellar.error.*
- 不引入任何 Spring 相关依赖
- 以 OpenTelemetry 标准语义为主,
STELLAR_*与stellspec_*仅作为输入桥接 - 保持和 Go SDK 一致的环境行为:开发环境看控制台,非开发环境走本机
log-agent - 给自研框架暴露通用
Appender/LoggerAPI,而不是强绑定某个日志实现
核心入口配置为 io.github.stellhub.stellspec.config.StellspecConfig,包含:
- 服务身份:
serviceName、serviceNamespace、serviceVersion、serviceInstanceId - 部署拓扑:
environment、cluster、region、zone、hostName、k8sNamespace、podName - 导出行为:
endpoint、protocol、output、format - 可靠性:
retry、fallbackFilePath、batchTimeout、exportTimeout
环境变量读取优先级:
- 代码显式传入
StellspecConfig stellspec_*OTEL_SERVICE_NAME/OTEL_RESOURCE_ATTRIBUTESSTELLAR_*- SDK 默认值
默认环境识别规则:
dev/local/development:视为开发环境- 其它环境:视为非开发环境
默认输出行为:
| 环境 | 默认输出 | 默认格式 | 默认端点 |
|---|---|---|---|
| 开发环境 | stdout |
console |
无 |
| 非开发环境 | otlp |
json |
http://localhost:4317 |
- OTLP exporter 默认重试:
- 首次重试间隔
5s - 最大重试间隔
30s - 总重试窗口
1m
- 首次重试间隔
- 导出最终失败后写入本地兜底文件:
- 默认路径:
logs/stellspec-fallback.log
- 默认路径:
- 超长日志正文在 SDK 内统一截断到
32 KiB- 自动补充
log.body_truncated - 自动补充
log.body_original_size - 自动补充
log.body_max_size
- 自动补充
仓库新增了一个不依赖 Spring 的适配器:
io.github.stellhub.stellspec.adapter.springboot.StellspecSpringBootAdapter
它适合由你的自研框架在自动装配阶段直接调用,内部已经固化好启动期优先级:
- 如果环境变量
LOG_STDOUT=true,或命令行参数传入--LOG_STDOUT=true - 如果存在
logback.configurationFile,或类路径下存在logback.xml/logback-spring.xml - 否则自动降级到
otel
仓库新增了:
io.github.stellhub.stellspec.bridge.logback.StellspecLogbackAppenderio.github.stellhub.stellspec.bridge.logback.StellspecLogbackBridgeInstallerio.github.stellhub.stellspec.bridge.logback.LogbackConfigurationDetector
在 OTEL 模式下,适配器会自动把 bridge 安装到 Logback Root Logger。
package demo;
import io.github.stellhub.stellspec.bridge.StellspecErrorDescriptor;
import io.github.stellhub.stellspec.bridge.StellspecLogger;
import io.github.stellhub.stellspec.config.RetryConfig;
import io.github.stellhub.stellspec.config.StellspecConfig;
import io.github.stellhub.stellspec.model.StellspecSeverity;
import io.github.stellhub.stellspec.sdk.StellspecRuntime;
import io.github.stellhub.stellspec.sdk.StellspecSdk;
import java.time.Duration;
import java.util.Map;
public final class DemoApplication {
private DemoApplication() {}
public static void main(String[] args) throws Exception {
StellspecConfig config =
StellspecConfig.builder()
.serviceName("order-service")
.serviceNamespace("stellar.trade")
.serviceVersion("1.0.0")
.environment("prod")
.development(false)
.output("otlp")
.protocol("grpc")
.endpoint("http://localhost:4317")
.fallbackFilePath("logs/stellspec-fallback.log")
.batchTimeout(Duration.ofSeconds(5))
.exportTimeout(Duration.ofSeconds(3))
.retry(
RetryConfig.builder()
.enabled(true)
.initialInterval(Duration.ofSeconds(5))
.maxInterval(Duration.ofSeconds(30))
.maxElapsedTime(Duration.ofMinutes(1))
.build())
.build();
StellspecRuntime runtime = StellspecSdk.create(config);
try {
StellspecLogger logger = runtime.createLogger("order-service");
logger.info("order created");
logger.log(
StellspecSeverity.ERROR,
"cancel order failed",
Map.of("order.id", "o-1001", "tenant.id", "t-01"),
new IllegalStateException("order already settled"),
StellspecErrorDescriptor.builder()
.code("FAILED_PRECONDITION")
.domain("trade.order")
.reason("ORDER_NOT_CANCELLABLE")
.retryable(false)
.build());
runtime.flush();
} finally {
runtime.shutdown();
}
}
}如果你的框架已经有自己的日志门面,只需要拿 Appender:
StellspecRuntime runtime = StellspecSdk.create();
var appender = runtime.createAppender("custom-framework");
appender.append(
io.github.stellhub.stellspec.bridge.StellspecLogEvent.builder()
.severity(io.github.stellhub.stellspec.model.StellspecSeverity.INFO)
.loggerName("custom-framework")
.message("request handled")
.attribute("http.request.method", "GET")
.attribute("http.response.status_code", 200)
.build());java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger("demo");
StellspecRuntime runtime = StellspecSdk.create();
julLogger.addHandler(new io.github.stellhub.stellspec.bridge.jul.StellspecJulHandler(
runtime.createAppender("jul-demo")));package demo;
import io.github.stellhub.stellspec.adapter.springboot.StellspecSpringBootAdapter;
public final class DemoBootstrap {
private DemoBootstrap() {}
public static void main(String[] args) throws Exception {
try (StellspecSpringBootAdapter adapter = StellspecSpringBootAdapter.initialize(args)) {
if (adapter.isOtelEnabled()) {
System.out.println("stellspec otel bridge enabled");
}
}
}
}StellspecRuntime create()StellspecRuntime create(StellspecConfig config)
StellspecAppender createAppender(String instrumentationScopeName)StellspecLogger createLogger(String instrumentationScopeName)void flush()void shutdown()
debug(String message)info(String message)warn(String message)error(String message, Throwable throwable)log(StellspecSeverity severity, String message, Map<String, ?> attributes, Throwable throwable, StellspecErrorDescriptor error)
STELLAR_APP_NAMESTELLAR_APP_NAMESPACESTELLAR_APP_VERSIONSTELLAR_APP_INSTANCE_IDSTELLAR_ENVSTELLAR_CLUSTERSTELLAR_REGIONSTELLAR_ZONESTELLAR_IDCSTELLAR_HOST_NAMESTELLAR_HOST_IPSTELLAR_NODE_NAMESTELLAR_K8S_NAMESPACESTELLAR_POD_NAMESTELLAR_POD_IPSTELLAR_CONTAINER_NAME
stellspec_SERVICE_NAMEstellspec_SERVICE_NAMESPACEstellspec_SERVICE_VERSIONstellspec_SERVICE_INSTANCE_IDstellspec_ENVIRONMENTstellspec_ENDPOINTstellspec_PROTOCOLstellspec_OUTPUTstellspec_FORMATstellspec_LEVELstellspec_INSECUREstellspec_DEVELOPMENTstellspec_ENABLE_CALLERstellspec_ENABLE_STACKTRACEstellspec_BATCH_TIMEOUTstellspec_EXPORT_TIMEOUTstellspec_MAX_BATCH_SIZEstellspec_MAX_QUEUE_SIZEstellspec_FALLBACK_FILE_PATHstellspec_RETRY_ENABLEDstellspec_RETRY_INITIAL_INTERVALstellspec_RETRY_MAX_INTERVALstellspec_RETRY_MAX_ELAPSED_TIMEstellspec_HEADERSstellspec_RESOURCE_ATTRIBUTES
src/main/java/io/github/stellhub/stellspec
├── bridge
│ ├── jul
│ ├── StellspecAppender.java
│ ├── StellspecErrorDescriptor.java
│ ├── StellspecLogEvent.java
│ └── StellspecLogger.java
├── config
├── exception
├── exporter
├── internal
├── model
└── sdk
mvn test当前仓库已通过 mvn test,包含:
- Spring Boot 模式优先级测试
- 配置优先级测试
- 正文截断测试
- 初始化链路 smoke test
独立示例位于: