iT邦幫忙

2025 iThome 鐵人賽

DAY 26
0

這篇要來介紹 Effect 與 Observability , Observability 中文叫可觀測性,意思是你的程式的執行的過程是可以被觀察的,特別是在分散式的系統或是微服務上,因為資料會在不同的地方被傳遞,因此如何觀察到這些資料是被如何處理的就變的至關重要了

一般講到 Observability 一般都會看到類似這樣的圖

https://ithelp.ithome.com.tw/upload/images/20251010/20111802yhM88La6G9.png
(圖片取自 opentelemetry.io)

上面的橫桿稱為 span ,每一條代表的是一段程式的執行,透過這樣的程式可以明確的看到程式間是如何互相呼叫的,與每段的執行時間等等

Effect 中的 Observability

那麼回到 Effect ,如果你之前有點開過這系列的文章中的那些我放在 Effect playground 的範例,你可能有注意到,左邊的側邊欄上一直有個 DevTools.ts 的檔案,那到底是做什麼用的呢?我們實際來使用一下,把裡面提供的 DevToolsLive 引入進來,並加入到我們上一篇中的 logging 的範例中,像這樣子

pipe(
  Effect.gen(function*() {
    yield* Effect.log('first')

    yield* Effect.sleep('500 millis')

    yield* Effect.log('second')
    
    yield* Effect.sleep('500 millis')

    yield* Effect.log('done')
  }),
  Effect.withLogSpan('span'),
  // 這個 withSpan 一定要加才有效果
  Effect.withSpan('main'),
  // 加入 DevToolsLive
  Effect.provide(DevToolsLive),
  Effect.runPromise
)

神奇的事發生了,我們看到下面的 trace viewer

https://ithelp.ithome.com.tw/upload/images/20251010/20111802PCz5iHTdGS.png

下面顯示出了我們程式 main 的執行時間,還有 log ,我們再來一個更複雜的範例

const taskA = Effect.fn("taskA")(function*() {
  yield* Effect.sleep("500 millis")
})

const taskC = Effect.fn("taskC")(function*() {
  yield* Effect.sleep("200 millis")
})

const taskB = Effect.fn("taskB")(function*(n: number) {
  // 將資料加到目前的 span 上
  yield* Effect.annotateCurrentSpan('n', n)
  yield* Effect.sleep("500 millis")
  yield* taskC()
})

pipe(
  Effect.gen(function*() {
    yield* Effect.log("first")
    yield* taskA()
    yield* Effect.log("second")
    yield* taskB(42)
    yield* Effect.log("done")
  }),
  Effect.withLogSpan("span"),
  Effect.withSpan("main"),
  Effect.provide(DevToolsLive),
  Effect.runPromise
)

這個範例給出了更複雜的 tracing ,我們還可以看到我們加在程式中的 n 被標記在 tracing 中

https://ithelp.ithome.com.tw/upload/images/20251010/20111802GyQkadrkzc.png

那上面的東西只有在 Effect playground 可以看到嗎?並不是的,如果你是本機開發使用,你可以安裝 Effect 的 vscode extension

那如果是正式環境呢?我們來看下去

正式環境中收集 tracing

如果是正式的環境,你會需要一個集中收集的服務,這邊我們使用 Axiom 這個免費額度還不錯的線上服務來 demo ,另外如果你想要自架,可以考慮看看 Grafana, OpenObserve 等也都不錯

如果要收集紀錄到遠端的服務的話,除了 effect 本體,你需要安裝不少的套件

$ pnpm add @effect/opentelemetry @opentelemetry/exporter-trace-otlp-http @opentelemetry/sdk-metrics @opentelemetry/sdk-trace-base @opentelemetry/sdk-trace-node @opentelemetry/sdk-trace-web

然後我們把 DevTool 改成 provide NodeSdk

import { NodeSdk } from '@effect/opentelemetry'
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'

  Effect.provide(
    NodeSdk.layer(() => ({
      resource: { serviceName: 'example' },
      spanProcessor: new BatchSpanProcessor(
        new OTLPTraceExporter({
          url: 'https://api.axiom.co/v1/traces',
          headers: {
            Authorization: 'Bearer <你的 API key>',
            'x-axiom-dataset': '<你的 dataset>',
          },
        }),
      ),
    })),
  )

事實上你沒看錯,這邊就是在使用 Open Telemetry 這個標準的 tracing 方法,這邊設定好後我們將程式執行一次,並到 Axiom 上看一下

https://ithelp.ithome.com.tw/upload/images/20251010/20111802SGO30HkcLA.png

https://ithelp.ithome.com.tw/upload/images/20251010/201118025QqLz5cHfn.png

像這樣,我們就可以收集正式環境的紀錄,並且使用這種方法了解程式內部是如何執行的,下一篇我們要來聊的是 Effect 內建的 Schema 驗證


上一篇
24. Effect logging
下一篇
26. Effect schema:資料格式驗證
系列文
Effect 魔法:打造堅不可摧的應用程式28
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言