上一篇文章中,我用 LongCounter
來計算收到的 event 數量,並且讓 OTEL 每一秒輸出一次資料到 log 裡。不過其實這個作法跟我本來想像的結果不太相同,因為我想像的是例如第一秒收到 5 個 event、第二秒收到 7 個 event,OTEL 輸出的 Metrics 應該要是:
- 第一個 data point 是 5
- 第二個 data point 是 7
- 第三個 data point 是 0
但事實上當時寫出來的範例程式會輸出的結果會是:
- 第一個 data point 是 5
- 第二個 data point 是 12
- 第三個 data point 是 12
也就是說,範例程式紀錄下來的是累計值,是從 application 啟動開始累計到現在的所有數值的加總。但我希望紀錄下來的其實是差異值,每次 Exporter 輸出完 Metrics 後,我希望它重置 counter。
設定 Exporter 輸出差異值
要達成紀錄的是差異值,要做的事情是去設定 Exporter 的 AggregationTemporality
。具體設定的方法其實每個 Exporter 都有點不一樣,不過都是在 ...Builder
的階段控制的。這裡繼續以 LoggingMetricExporter
為例,LoggingMetricExporter
設定 temporality 的方法如下:
LoggingMetricExporter.create(AggregationTemporality.DELTA);
測試方法
設定了 AggregationTemporality
之後,把測試的腳本稍微弄複雜一點,大體來說就是改成用 2 個 thread 模擬送出 1M 個 event,然後觀察 OTEL 紀錄到什麼東西。為了簡化測試,我把一些本來隨機的東西都拿掉,會比較方便觀察數字的正確性 XD。
@Override
public void run(String... args) throws Exception {
log.info("Run");
produceEvents(1_000_000, 10);
log.info("Done");
}
private void produceEvents(int numOfEvents, int numOfThreads) {
var executor = Executors.newFixedThreadPool(numOfThreads);
for (int i = 0; i < numOfEvents; i++) {
executor.submit(() -> {
if (random.nextBoolean()) {
processor1.receiveEvent(generateRandomEvent());
} else {
processor2.receiveEvent(generateRandomEvent());
}
});
}
}
private Event generateRandomEvent() {
var eventType = "create";
return Event.builder()
.eventType(eventType)
.owner("owner-1")
.build();
}
完整的範例程式可以參考這裡。
執行結果
以下是執行時,OTEL 輸出的結果。
INFO i.o.e.l.LoggingMetricExporter [PeriodicMetricReader-1] Received a collection of 1 metrics for export.
INFO i.o.e.l.LoggingMetricExporter [PeriodicMetricReader-1] metric: ImmutableMetricData{resource=Resource{schemaUrl=null, attributes={service.name="otel-example", telemetry.sdk.language="java", telemetry.sdk.name="opentelemetry", telemetry.sdk.version="1.22.0"}}, instrumentationScopeInfo=InstrumentationScopeInfo{name=event-consumer, version=1.0.0, schemaUrl=null, attributes={}}, name=eventType, description=Metrics for the event consuming., unit=1, type=LONG_SUM, data=ImmutableSumData{points=[ImmutableLongPointData{startEpochNanos=1682522136538247300, epochNanos=1682522137553247500, attributes={eventType="create", owner="owner-1"}, value=584412, exemplars=[]}], monotonic=true, aggregationTemporality=DELTA}}
INFO i.o.e.l.LoggingMetricExporter [PeriodicMetricReader-1] Received a collection of 1 metrics for export.
INFO i.o.e.l.LoggingMetricExporter [PeriodicMetricReader-1] metric: ImmutableMetricData{resource=Resource{schemaUrl=null, attributes={service.name="otel-example", telemetry.sdk.language="java", telemetry.sdk.name="opentelemetry", telemetry.sdk.version="1.22.0"}}, instrumentationScopeInfo=InstrumentationScopeInfo{name=event-consumer, version=1.0.0, schemaUrl=null, attributes={}}, name=eventType, description=Metrics for the event consuming., unit=1, type=LONG_SUM, data=ImmutableSumData{points=[ImmutableLongPointData{startEpochNanos=1682522137553247500, epochNanos=1682522138548844500, attributes={eventType="create", owner="owner-1"}, value=415588, exemplars=[]}], monotonic=true, aggregationTemporality=DELTA}}
DEBUG i.o.s.m.e.PeriodicMetricReader [PeriodicMetricReader-1] No metric data to export - skipping export.
DEBUG i.o.s.m.e.PeriodicMetricReader [PeriodicMetricReader-1] No metric data to export - skipping export.
文字太長了,稍微摘要一下:
....attributes={eventType="create", owner="owner-1"}, value=584412, exemplars=[]....
....attributes={eventType="create", owner="owner-1"}, value=415588, exemplars=[]....
....No metric data to export - skipping export.
....No metric data to export - skipping export.
可以看到它第一秒紀錄到的 count 是 584,412、第二秒紀錄到的是 415,588,兩秒合計就是 1M,正好是我的測試程式送出的數目。兩秒過去後,因為後續沒有再呼叫 method,所以 OTEL 沒有繼續收到新的 metric data,就會看到 skipping export 的訊息。