ওপেনটেলিমেট্রি ট্রেসিংয়ের আমার ডেমোতে দুটি স্প্রিং বুট উপাদান রয়েছে। একজন জাভা এজেন্ট ব্যবহার করে, এবং আমি একটি ভিন্ন আচরণ লক্ষ্য করেছি যখন আমি সম্প্রতি এটিকে v1.x থেকে v2.x এ আপগ্রেড করেছি। অন্যটিতে, আমি মাইক্রোমিটার ট্রেসিং ব্যবহার করছি কারণ আমি GraalVM নেটিভ কম্পাইল করি, এবং এটি জাভা এজেন্টকে প্রক্রিয়া করতে পারে না।
এই পোস্টে, আমি এই তিনটি পদ্ধতির তুলনা করতে চাই: জাভা এজেন্ট v1, জাভা এজেন্ট v2 এবং মাইক্রোমিটার ট্রেসিং।
বেস অ্যাপ্লিকেশন এবং এর অবকাঠামো
আমি একই বেস অ্যাপ্লিকেশন ব্যবহার করব: একটি সাধারণ স্প্রিং বুট অ্যাপ্লিকেশন, কোটলিনে কোড করা। এটি একটি একক শেষ পয়েন্ট অফার করে।
- শেষবিন্দুর বাইরের ফাংশনটির নাম
entry()
- এটি
intermediate()
নামে আরেকটি ফাংশনকে কল করে - পরেরটি একটি
WebClient
উদাহরণ ব্যবহার করে,RestTemplate
এর প্রতিস্থাপন, উপরের এন্ডপয়েন্টে কল করার জন্য - অসীম লুপিং এড়াতে, আমি একটি কাস্টম অনুরোধ শিরোনাম পাস করি: যদি
entry()
ফাংশনটি এটি খুঁজে পায় তবে এটি আর এগিয়ে যাবে না
এটি নিম্নলিখিত কোডে অনুবাদ করে:
@SpringBootApplication class Agent1xApplication @RestController class MicrometerController { private val logger = LoggerFactory.getLogger(MicrometerController::class.java) @GetMapping("/{message}") fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) { logger.info("entry: $message") if (done == null) intermediate() } fun intermediate() { logger.info("intermediate") RestClient.builder() .baseUrl("http://localhost:8080/done") .build() .get() .header("X-done", "true") .retrieve() .toBodilessEntity() } }
প্রতিটি সেটআপের জন্য, আমি দুটি পর্যায় পরীক্ষা করব: প্রাথমিক পর্যায়, OpenTelemetry সক্ষম সহ, এবং অতিরিক্ত অভ্যন্তরীণ স্প্যান তৈরি করার জন্য একটি কাস্টমাইজেশন পর্যায়।
মাইক্রোমিটার ট্রেসিং
মাইক্রোমিটার ট্রেসিং মাইক্রোমিটার থেকে উদ্ভূত হয়, এটি একটি "বিক্রেতা-নিরপেক্ষ অ্যাপ্লিকেশন অবজারভেবিলিটি ফ্যাকেড"।
মাইক্রোমিটার ট্রেসিং সবচেয়ে জনপ্রিয় ট্রেসার লাইব্রেরিগুলির জন্য একটি সাধারণ সম্মুখভাগ প্রদান করে, যা আপনাকে বিক্রেতা লক-ইন ছাড়াই আপনার JVM-ভিত্তিক অ্যাপ্লিকেশন কোডের উপকরণ দিতে দেয়। এটি এমনভাবে ডিজাইন করা হয়েছে যাতে আপনার ট্রেসিং সংগ্রহের ক্রিয়াকলাপে সামান্য থেকে কোন ওভারহেড যোগ না করা যায় এবং আপনার ট্রেসিং প্রচেষ্টার বহনযোগ্যতাকে সর্বাধিক করা হয়।
মাইক্রোমিটার ট্রেসিং দিয়ে শুরু করতে, একজনকে কয়েকটি নির্ভরতা যোগ করতে হবে:
- স্প্রিং বুট অ্যাকচুয়েটর,
org.springframework.boot:spring-boot-starter-actuator
- মাইক্রোমিটার নিজেই ট্রেসিং,
io.micrometer:micrometer-tracing
- লক্ষ্য ট্রেসিং ব্যাকএন্ড API-এ একটি "সেতু"। আমার ক্ষেত্রে, এটি OpenTelemetry, তাই
io.micrometer:micrometer-tracing-bridge-otel
- ব্যাকএন্ডে একটি কংক্রিট রপ্তানিকারক,
io.opentelemetry:opentelemetry-exporter-otlp
আমাদের একটি BOM দরকার নেই কারণ সংস্করণগুলি ইতিমধ্যেই স্প্রিং বুট প্যারেন্টে সংজ্ঞায়িত করা হয়েছে।
তবুও, আমাদের দুটি রানটাইম কনফিগারেশন প্যারামিটার দরকার: ট্রেসগুলি কোথায় পাঠানো উচিত এবং উপাদানটির নাম কী। এগুলি MANAGEMENT_OTLP_TRACING_ENDPOINT
এবং SPRING_APPLICATION_NAME
ভেরিয়েবল দ্বারা নিয়ন্ত্রিত৷
services: jaeger: image: jaegertracing/all-in-one:1.55 environment: - COLLECTOR_OTLP_ENABLED=true #1 ports: - "16686:16686" micrometer-tracing: build: dockerfile: Dockerfile-micrometer environment: MANAGEMENT_OTLP_TRACING_ENDPOINT: http://jaeger:4318/v1/traces #2 SPRING_APPLICATION_NAME: micrometer-tracing #3
- Jaeger-এর জন্য OpenTelemetry সংগ্রাহক সক্ষম করুন
- Jaeger OpenTelemetry gRPC এন্ডপয়েন্টের সম্পূর্ণ URL
- OpenTelemetry এর পরিষেবার নাম সেট করুন
এখানে ফলাফল:
কোনো কাস্টমাইজেশন ছাড়াই, মাইক্রোমিটার স্প্যান তৈরি করে যখন HTTP অনুরোধ গ্রহণ এবং পাঠানো হয়।
ফ্রেমওয়ার্ক পাঠানোর জন্য RestClient
এ যাদু ইনজেক্ট করতে হবে। আমাদের অবশ্যই পূর্ববর্তীটিকে তার জন্য পরবর্তীটিকে তাত্ক্ষণিক করতে দিতে হবে:
@SpringBootApplication class MicrometerTracingApplication { @Bean fun restClient(builder: RestClient.Builder) = builder.baseUrl("http://localhost:8080/done").build() }
আমরা বিভিন্ন উপায়ে ম্যানুয়াল স্প্যান তৈরি করতে পারি, একটি OpenTelemetry API এর মাধ্যমে। যাইহোক, সেটআপের জন্য প্রচুর বয়লারপ্লেট কোড প্রয়োজন। সবচেয়ে সহজ উপায় হল মাইক্রোমিটারের পর্যবেক্ষণ API । এর প্রধান সুবিধা হল একটি একক API ব্যবহার করা যা মেট্রিক্স এবং ট্রেস উভয়ই পরিচালনা করে।
এখানে আপডেট করা কোড:
class MicrometerController( private val restClient: RestClient, private val registry: ObservationRegistry ) { @GetMapping("/{message}") fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) { logger.info("entry: $message") val observation = Observation.start("entry", registry) if (done == null) intermediate(observation) observation.stop() } fun intermediate(parent: Observation) { logger.info("intermediate") val observation = Observation.createNotStarted("intermediate", registry) .parentObservation(parent) .start() restClient.get() .header("X-done", "true") .retrieve() .toBodilessEntity() observation.stop() } }
যোগ করা পর্যবেক্ষণ কলগুলি উত্পন্ন ট্রেসগুলির উপর প্রতিফলিত হয়:
OpenTelemetry Agent v1
মাইক্রোমিটার ট্রেসিংয়ের একটি বিকল্প হল জেনেরিক ওপেনটেলিমেট্রি জাভা এজেন্ট । এর প্রধান সুবিধা হল এটি কোড বা ডেভেলপারদেরকে প্রভাবিত করে না; এজেন্ট একটি বিশুদ্ধ রানটাইম-স্কোপড উদ্বেগ.
java -javaagent:opentelemetry-javaagent.jar agent-one-1.0-SNAPSHOT.jar
এজেন্ট পরিবেশের ভেরিয়েবলের সাথে OpenTelemetry এর কনফিগারেশন মেনে চলে:
services: agent-1x: build: dockerfile: Dockerfile-agent1 environment: OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4317 #1 OTEL_RESOURCE_ATTRIBUTES: service.name=agent-1x #2 OTEL_METRICS_EXPORTER: none #3 OTEL_LOGS_EXPORTER: none #4 ports: - "8081:8080"
- প্রোটোকল, ডোমেইন এবং পোর্ট সেট করুন। লাইব্রেরি
/v1/traces
যুক্ত করে - OpenTelemetry এর পরিষেবার নাম সেট করুন
- মেট্রিক্স বা লগ উভয়ই রপ্তানি করুন
আর কোন কনফিগারেশন ছাড়া, আমরা নিম্নলিখিত ট্রেস পেতে পারি:
এজেন্ট স্বয়ংক্রিয়ভাবে অনুরোধগুলি ট্র্যাক করে, প্রাপ্ত এবং পাঠানো উভয়ই, সেইসাথে স্প্রিং-সম্পর্কিত টীকা দিয়ে চিহ্নিত ফাংশনগুলি । কল স্ট্যাক অনুসারে ট্রেসগুলি একে অপরের ভিতরে সঠিকভাবে নেস্ট করা হয়। অতিরিক্ত ফাংশন ট্রেস করতে, আমাদের কোডবেসে একটি নির্ভরতা যোগ করতে হবে, io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations
। আমরা এখন @WithSpan
টীকা দিয়ে পূর্বে অনুসৃত ফাংশন টীকা করতে পারি।
value()
অংশটি ট্রেসের লেবেলকে নিয়ন্ত্রণ করে, যখন kind
একটি span.kind
বৈশিষ্ট্য হিসাবে অনুবাদ করে। যদি মানটি একটি খালি স্ট্রিং-এ সেট করা থাকে, যা ডিফল্ট, এটি ফাংশনের নাম আউটপুট করে। আমার উদ্দেশ্যে, ডিফল্ট মান যথেষ্ট ভাল।
@WithSpan fun intermediate() { logger.info("intermediate") RestClient.builder() .baseUrl("http://localhost:8080/done") .build() .get() .header("X-done", "true") .retrieve() .toBodilessEntity() }
এটি প্রত্যাশিত নতুন intermediate()
ট্রেস প্রদান করে:
OpenTelemetry Agent v2
OpenTelemetry এই বছরের জানুয়ারিতে এজেন্টের একটি নতুন প্রধান সংস্করণ প্রকাশ করেছে। আমি এটি দিয়ে আমার ডেমো আপডেট করেছি; ট্রেসগুলি এখন শুধুমাত্র তখনই তৈরি হয় যখন অ্যাপটি অনুরোধ গ্রহণ করে এবং পাঠায়।
পূর্ববর্তী সংস্করণ হিসাবে, আমরা @WithSpan
টীকা দিয়ে ট্রেস যোগ করতে পারি। শুধুমাত্র পার্থক্য হল যে আমাদের অবশ্যই entry()
ফাংশনটি টীকা দিতে হবে। এটি ডিফল্টরূপে ট্রেস করা হয় না.
আলোচনা
স্প্রিং দুটি কারণে সফল হয়েছে: এটি জটিল সমাধানগুলিকে সরলীকৃত করেছে, যেমন , EJBs 2, এবং প্রতিযোগী লাইব্রেরির উপর একটি বিমূর্ত স্তর প্রদান করেছে। মাইক্রোমিটার ট্রেসিং জিপকিন এবং জেগারের উপর একটি বিমূর্ত স্তর হিসাবে শুরু হয়েছিল এবং এটি সম্পূর্ণ অর্থবহ ছিল। ওপেনটেলিমেট্রি প্রোগ্রামিং ভাষা এবং ট্রেস সংগ্রাহক জুড়ে বেশিরভাগ লাইব্রেরি দ্বারা সমর্থিত হওয়ায় এই যুক্তিটি বিতর্কিত হয়ে ওঠে। পর্যবেক্ষণ API এখনও মাইক্রোমিটার ট্রেসিংয়ের একটি উল্লেখযোগ্য সুবিধা, কারণ এটি মেট্রিক্স এবং ট্রেসের উপর একটি একক API ব্যবহার করে।
জাভা এজেন্টের দিকে, ওপেনটেলিমেট্রি কনফিগারেশন সমস্ত টেক স্ট্যাক এবং লাইব্রেরি - পরিবেশ ভেরিয়েবল জুড়ে একই রকম। আমি যখন v1 থেকে v2 তে আপগ্রেড করেছিলাম তখন আমি কিছুটা হতাশ হয়েছিলাম, কারণ নতুন এজেন্ট স্প্রিং-সচেতন নয়: স্প্রিং-টীকাযুক্ত ফাংশনগুলি ডিফল্টরূপে ট্রেস করা হয় না।
শেষ পর্যন্ত, এটি একটি বুদ্ধিমান সিদ্ধান্ত। আপনি দেখতে চান না এমন কিছু সরানোর চেয়ে আপনি যে স্প্যানগুলি চান সেগুলি সম্পর্কে স্পষ্ট হওয়া অনেক ভাল৷
জোনাটান ইভানভকে তার সাহায্য এবং তার পর্যালোচনার জন্য ধন্যবাদ ।
এই পোস্টের জন্য সম্পূর্ণ উৎস কোড GitHub এ পাওয়া যাবে:
আরও যেতে:
- OpenTelemetry ট্রেসিং এর ডেমো
- মাইক্রোমিটার ট্রেসিং
- ওপেনটেলিমেট্রি ট্রেস
- ওপেনটেলিমেট্রি জাভা ইন্টিগ্রেশন
- ওপেনটেলিমেট্রি জাভা উদাহরণ
- স্প্রিং বুট 3 এর সাথে বিতরণ করা ট্রেসিং — মাইক্রোমিটার বনাম ওপেনটেলিমেট্রি
- স্প্রিং বুট 3 সহ পর্যবেক্ষণযোগ্যতা
মূলত 3রা আগস্ট, 2024-এ A Java Geek এ প্রকাশিত