اتصال Java و Spring Boot

در این آموزش
  1. گام ۱: دانلود agent
  2. گام ۲: اجرای برنامه با agent
  3. Docker و Kubernetes: با متغیرهای محیطی
  4. نوشتن لاگ در Spring Boot
  5. ویژگی‌های MDC
  6. عیب‌یابی
  7. منابع و مطالعهٔ بیشتر

برای Java ساده‌ترین راه، OpenTelemetry Java Agent است: یک فایل jar که هنگام اجرای برنامه کنار آن بارگذاری می‌شود و لاگ‌های Logback و Log4j2 را بدون تغییر کد می‌گیرد و می‌فرستد. Spring Boot 3 به‌طور پیش‌فرض Logback دارد، پس معمولاً هیچ خط کدی عوض نمی‌شود.

گام ۱: دانلود agent

آخرین نسخهٔ agent را از صفحهٔ انتشار رسمی پروژهٔ OpenTelemetry بگیرید:

curl -L -o opentelemetry-javaagent.jar \
  https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar

agent با Java 8 به بعد کار می‌کند. فایل را کنار jar برنامه یا در مسیر ثابتی مثل /opt/otel/ بگذارید.

گام ۲: اجرای برنامه با agent

تنظیمات را با system propertyها بدهید:

java -javaagent:opentelemetry-javaagent.jar \
  -Dotel.service.name=orders-service \
  -Dotel.resource.attributes=deployment.environment.name=production \
  -Dotel.logs.exporter=otlp \
  -Dotel.traces.exporter=none \
  -Dotel.metrics.exporter=none \
  -Dotel.exporter.otlp.logs.protocol=http/protobuf \
  -Dotel.exporter.otlp.logs.endpoint=https://ingest.logmug.ir/v1/logs \
  -Dotel.exporter.otlp.logs.headers=x-logmug-key=lm_ingest_... \
  -jar app.jar

معنی هر خط:

  • otel.service.name ستون «سرویس» را پر می‌کند و deployment.environment.name ستون «محیط» را. نام میزبان را agent خودش اضافه می‌کند.
  • otel.traces.exporter=none و otel.metrics.exporter=none لازم‌اند چون LogMug فقط لاگ می‌پذیرد. با این تنظیم، agent همچنان trace را درون برنامه می‌سازد، پس لاگ‌ها trace_id دارند؛ فقط آن را جایی نمی‌فرستد.
  • endpoint مخصوص لاگ باید مسیر کامل /v1/logs را داشته باشد.

Docker و Kubernetes: با متغیرهای محیطی

همین تنظیمات را می‌توان با متغیرهای محیطی استاندارد داد، که برای کانتینرها راحت‌تر است و کلید را از خط فرمان بیرون نگه می‌دارد:

JAVA_TOOL_OPTIONS=-javaagent:/opt/otel/opentelemetry-javaagent.jar
OTEL_SERVICE_NAME=orders-service
OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=production
OTEL_LOGS_EXPORTER=otlp
OTEL_TRACES_EXPORTER=none
OTEL_METRICS_EXPORTER=none
OTEL_EXPORTER_OTLP_LOGS_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://ingest.logmug.ir/v1/logs
OTEL_EXPORTER_OTLP_LOGS_HEADERS=x-logmug-key=lm_ingest_...

یک Dockerfile نمونه:

FROM eclipse-temurin:21-jre
WORKDIR /app
ADD https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar /opt/otel/opentelemetry-javaagent.jar
COPY target/app.jar app.jar
ENV JAVA_TOOL_OPTIONS="-javaagent:/opt/otel/opentelemetry-javaagent.jar"
ENTRYPOINT ["java", "-jar", "app.jar"]

در Kubernetes، کلید را در یک Secret بگذارید و با valueFrom.secretKeyRef به متغیر OTEL_EXPORTER_OTLP_LOGS_HEADERS بدهید. برای ساخت محیط‌های تکرارپذیر، نسخهٔ agent را به‌جای latest ثابت کنید.

نوشتن لاگ در Spring Boot

کد همان SLF4J همیشگی است. استثنا را آخرین آرگومان بدهید تا نوع، پیام و stack trace جدا ذخیره شوند:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
public class PaymentService {
    private static final Logger log = LoggerFactory.getLogger(PaymentService.class);

    public void pay(long orderId) {
        try {
            // ...
            log.info("Order {} paid", orderId);
        } catch (Exception e) {
            log.error("Payment failed for order {}", orderId, e);
            throw e;
        }
    }
}

سطح‌ها خودکار نگاشت می‌شوند (WARN به warn، ERROR به error و مانند آن). فیلتر سطح همان تنظیم معمول Spring است، مثلاً logging.level.root=INFO در application.properties؛ agent فقط لاگ‌هایی را می‌فرستد که از این فیلتر رد شوند.

ویژگی‌های MDC

اگر شناسه‌هایی مثل userId یا tenant را در MDC می‌گذارید و می‌خواهید در LogMug قابل‌فیلتر باشند، گرفتن آن‌ها را فعال کنید (این گزینه در agent برچسب experimental دارد):

-Dotel.instrumentation.logback-appender.experimental.capture-mdc-attributes=*

برای Log4j2 معادل آن otel.instrumentation.log4j-appender.experimental.capture-mdc-attributes است. شناسهٔ trace جداگانه و بدون این تنظیم فرستاده می‌شود. دربارهٔ اینکه چرا یک شناسهٔ مشترک برای کل درخواست این‌قدر کمک می‌کند، مقالهٔ trace_id و correlation id را ببینید.

عیب‌یابی

agent هنگام شروع چند خط با پیشوند [otel.javaagent] در خروجی می‌نویسد. اگر این خطوط را نمی‌بینید، agent اصلاً بارگذاری نشده است (مسیر -javaagent یا JAVA_TOOL_OPTIONS را بررسی کنید). برای جزئیات بیشتر موقتاً -Dotel.javaagent.debug=true بگذارید.

  • 401: کلید نادرست یا باطل‌شده است، یا قالب هدر اشتباه است؛ باید x-logmug-key=lm_ingest_... باشد.
  • 400: بدنه خوانده نشد؛ مطمئن شوید پروتکل http/protobuf است و پراکسی میانی بدنه را تغییر نمی‌دهد.
  • 403: سهمیهٔ ماهانهٔ پلن رایگان تمام شده است؛ سهمیه‌ها را ببینید.
  • 429 و 503: عبور از نرخ مجاز یا شلوغی موقت؛ exporter دسته را دوباره می‌فرستد.
  • خطاهای اتصال به /v1/traces یا /v1/metrics در لاگ agent: exporter trace یا metric روشن مانده است؛ هر دو را none کنید.
  • سرویس unknown_service:java است: otel.service.name اعمال نشده است.

منابع و مطالعهٔ بیشتر

کلید پروژه‌تان را هنوز ندارید؟

در پلن رایگان یک پروژه بسازید؛ راهنمای اتصال با نشانی و کلید واقعی خودتان همان‌جا آماده است.

شروع رایگان