Tampilan
8.1 Tracing
Tujuan bab
Setelah bab ini kamu bisa:
- Mengaktifkan observability dan menjelaskan apa yang direkam sebuah trace
- Membaca satu trace untuk mendiagnosis agent yang berperilaku aneh
- Mengurangi kebisingan dan biaya dengan sampling,
excludeSpanTypes, danspanFilter - Menjelaskan peran
sensitiveDataFilterdan kenapa ia menyala secara default - Mengambil metadata dari request context ke dalam trace
Prasyarat
- Bagian 7 selesai
- Storage terpasang
Apa yang direkam sebuah trace
Ingat dari 1.1 bahwa agent adalah loop, dan dari 2.3 bahwa satu pertanyaan dengan tool berarti beberapa panggilan model. Semua itu tidak terlihat dari luar — kamu hanya melihat pertanyaan masuk dan jawaban keluar.
Trace membuka kotak hitam itu. Ia merekam tiap operasi sebagai span, dan span-span itu tersusun secara hierarkis.
Trace: "Cuaca di Surabaya dan Jakarta?" 2.4 dtk
├── Agent run 2.4 dtk
│ ├── Model call #1 0.6 dtk
│ │ └── keputusan: panggil get-weather ×2
│ ├── Tool: get-weather (Surabaya) 0.3 dtk
│ ├── Tool: get-weather (Jakarta) 1.1 dtk ← lambat
│ └── Model call #2 0.4 dtk
│ └── jawaban akhirDari satu gambar itu kamu langsung tahu ke mana waktu pergi, tool apa yang dipanggil dengan argumen apa, dan berapa kali model dipanggil. Pertanyaan yang sebelumnya butuh sepuluh console.log terjawab dalam sekali lihat.
Mengaktifkannya
Tracing dikonfigurasi lewat paket terpisah, @mastra/observability:
bash
npm install @mastra/observability@latestts
// src/mastra/index.ts
import { Mastra } from '@mastra/core/mastra'
import { LibSQLStore } from '@mastra/libsql'
import {
Observability,
MastraStorageExporter,
SensitiveDataFilter,
} from '@mastra/observability'
export const mastra = new Mastra({
storage: new LibSQLStore({ id: 'mastra-storage', url: 'file:./mastra.db' }),
observability: new Observability({
configs: {
default: {
serviceName: 'mastra',
exporters: [new MastraStorageExporter()],
spanOutputProcessors: [new SensitiveDataFilter()],
},
},
}),
})observability menerima instance, bukan objek konfigurasi
Ini titik yang mudah salah. Properti observability pada Mastra bertipe ObservabilityEntrypoint — sebuah objek yang sudah di-instantiasi, bukan objek konfigurasi biasa.
Bentuk seperti observability: { default: { enabled: true } } yang muncul di sebagian contoh akan ditolak compiler:
Object literal may only specify known properties,
and 'default' does not exist in type 'ObservabilityEntrypoint'Yang benar: bungkus konfigurasimu dengan new Observability({ ... }) dari @mastra/observability. Objek konfigurasi yang kamu berikan ke dalam konstruktor itulah yang bentuknya ObservabilityRegistryConfig — dan di situlah default, configs, dan sensitiveDataFilter berada.
Untuk mulai cepat, bentuk paling ringkas cukup begini:
ts
observability: new Observability({
default: { enabled: true },
}),default: { enabled: true } menyalakan konfigurasi bawaan lengkap dengan exporter ke storage Mastra dan ke platform Mastra. Contoh eksplisit di atas setara dengan ini, tapi memperlihatkan bagian-bagiannya — dan itu yang kamu butuhkan begitu ingin menyesuaikan sesuatu.
Tiga bagian yang kamu susun di dalamnya:
| Bagian | Perannya |
|---|---|
serviceName | Nama layanan yang muncul di trace |
exporters | Ke mana data trace dikirim |
spanOutputProcessors | Pemroses span sebelum diekspor — termasuk penyensor data sensitif |
Exporter menentukan tujuan. MastraStorageExporter menulis ke storage yang kamu konfigurasi; MastraPlatformExporter mengirim ke platform Mastra. Keduanya bisa dipakai bersamaan:
ts
exporters: [new MastraStorageExporter(), new MastraPlatformExporter()],Trace-nya bisa langsung kamu lihat di Studio — dan inilah kenapa kebiasaan membuka Studio yang dianjurkan sejak 1.1 mulai terbayar.
Konfigurasi yang lebih terkendali
Nama konfigurasi tidak harus default. Kamu bisa memberi nama sesuai lingkungan dan menyetel perilakunya lebih rinci:
ts
// src/mastra/index.ts
import { Mastra } from '@mastra/core/mastra'
import { LibSQLStore } from '@mastra/libsql'
import { Observability, MastraStorageExporter } from '@mastra/observability'
export const mastra = new Mastra({
storage: new LibSQLStore({ id: 'mastra-storage', url: 'file:./mastra.db' }),
observability: new Observability({
configs: {
produksi: {
serviceName: 'layanan-support',
exporters: [new MastraStorageExporter()],
includeInternalSpans: false,
requestContextKeys: ['tenantId', 'userId'],
},
},
}),
})Properti yang paling berpengaruh:
| Properti | Kegunaan |
|---|---|
serviceName | Nama layanan yang muncul di trace |
sampling | Strategi pengambilan sampel — default merekam semuanya |
exporters | Ke mana data trace dikirim |
includeInternalSpans | Menyertakan span internal operasi Mastra |
excludeSpanTypes | Jenis span yang tidak diekspor |
spanFilter | Fungsi penyaring: kembalikan true untuk menyimpan |
requestContextKeys | Kunci RequestContext yang diambil sebagai metadata |
requestContextKeys — menghubungkan trace ke penggunanya
Ini yang membuat trace berguna di produksi. Tanpa metadata, kamu punya ribuan trace tanpa cara memfilternya. Dengan requestContextKeys, nilai dari RequestContext — tenantId, userId, plan — ikut terekam sebagai metadata trace.
Sekarang saat seorang pelanggan melapor "asisten memberi jawaban salah tadi pagi", kamu bisa mencari trace miliknya, bukan menebak.
Perhatikan bahwa properti ini mendukung notasi titik, sehingga nilai bersarang juga bisa diambil.
Mengurangi kebisingan dan biaya
Merekam semuanya bagus saat pengembangan dan mahal di produksi — terutama pada platform yang menagih per span.
Tiga tuas tersedia, dan urutan penerapannya penting:
excludeSpanTypes → spanOutputProcessors → spanFilterDokumentasi menyebut bahwa spanFilter berjalan setelah excludeSpanTypes dan spanOutputProcessors.
sampling — default-nya ALWAYS, artinya semua direkam. Turunkan untuk lalu lintas tinggi.
excludeSpanTypes — buang jenis span tertentu sama sekali. Berguna untuk mengurangi kebisingan pada platform dengan penagihan per span.
spanFilter — fungsi yang mengembalikan true untuk menyimpan dan false untuk membuang. Ini yang paling luwes: kamu bisa, misalnya, merekam semua trace yang gagal dan hanya sebagian kecil yang berhasil.
Pola yang berguna di produksi
Simpan semua trace yang mengandung error, dan sebagian kecil yang sukses. Trace yang sukses sebagian besar seragam; trace yang gagal justru selalu berbeda, dan itu yang kamu butuhkan saat mendiagnosis.
Data sensitif
Ini perilaku default yang penting diketahui, karena melindungimu dari kesalahan yang mudah terjadi.
sensitiveDataFilter menyala secara default. Ia otomatis diterapkan ke tiap instance observability yang dikonfigurasi, menyensor field yang dianggap sensitif.
Letaknya di konstruktor Observability, sejajar dengan configs:
ts
observability: new Observability({
configs: { /* ... */ },
sensitiveDataFilter: false, // ← mematikannya, jangan lakukan ini
}),Kamu bisa mematikannya dengan false, atau menyesuaikannya dengan objek opsi untuk mengatur field mana yang disensor, token penggantinya, dan gaya penyensorannya.
Pikirkan dua kali sebelum mematikannya
Trace merekam argumen tool dan isi pesan. Tanpa penyaring, itu berarti nomor kartu, token, dan data pribadi pengguna ikut tersimpan di sistem observability-mu — sering kali dengan retensi panjang dan akses yang lebih longgar daripada basis data utamamu.
Kalau kamu perlu melihat nilai yang tersensor untuk diagnosis, sesuaikan daftar field-nya alih-alih mematikan penyaringnya.
Dua catatan tambahan dari dokumentasi: kalau sebuah konfigurasi sudah memuat SensitiveDataFilter di spanOutputProcessors, ia tidak diduplikasi. Dan instance yang sudah di-instantiasi sebelumnya tidak dimodifikasi.
Membaca trace untuk diagnosis
Tiga pola yang paling sering kamu cari:
Agent lambat. Lihat durasi tiap span. Biasanya penyebabnya salah satu dari dua: satu tool yang lambat, atau terlalu banyak putaran loop. Yang pertama masalah integrasi; yang kedua biasanya masalah instruksi yang ambigu.
Agent memanggil tool yang salah. Lihat argumen pada span tool. Sering kali argumennya sendiri sudah aneh, yang menunjuk ke description atau schema yang kurang jelas — kembali ke 2.2.
Agent mengabaikan konteks RAG. Lihat apakah span tool pencarian benar-benar mengembalikan potongan yang relevan. Kalau ya, tapi jawabannya tetap melenceng, masalahnya di instruksi — persis kegagalan ketiga yang dibahas di 5.1.
Memeriksa dari baris perintah
Selain Studio, Mastra menyediakan CLI untuk memeriksa trace tanpa membuka peramban:
bash
npx mastra api trace listPerintah ini memerlukan server Mastra yang berjalan. Jalankan npx mastra dev, atau berikan URL server yang bisa dijangkau lewat --url.
Ini berguna saat kamu mendiagnosis di lingkungan tanpa antarmuka grafis, atau saat ingin menyaring trace dengan perkakas baris perintah biasa.
Kesalahan umum
Gejala: Biaya platform observability melonjak setelah aplikasi masuk produksi, padahal saat pengembangan terasa wajar. Penyebab: Sampling masih pada nilai bawaan ALWAYS, yang merekam semua span dari semua permintaan. Volume produksi berbeda beberapa orde besaran dari volume pengembangan. Perbaikan: Turunkan sampling, buang jenis span yang tidak kamu pakai lewat excludeSpanTypes, dan pertimbangkan spanFilter yang menyimpan semua trace gagal tapi hanya sebagian trace sukses.
Gejala: Ada ribuan trace tersimpan, tapi saat seorang pengguna melapor masalah, kamu tidak bisa menemukan trace miliknya. Penyebab: Tidak ada metadata yang menghubungkan trace ke pengguna atau tenant. Perbaikan: Isi requestContextKeys dengan kunci seperti userId dan tenantId, dan pastikan nilai-nilai itu memang diisi ke RequestContext di sisi server — caranya di 9.2.
Coba sendiri
Tantangan: Aktifkan tracing pada agent yang sudah kamu bangun, lalu pakai trace itu untuk menemukan masalah yang sengaja kamu tanam.
Ketentuan:
- Aktifkan observability dengan
default: { enabled: true }pada agent yang punya minimal tiga tool - Jalankan lima pertanyaan berbeda dan periksa trace-nya di Studio
- Untuk satu trace, catat: berapa kali model dipanggil, tool apa saja yang dipanggil, dan span mana yang paling lama
- Tanam masalah: tambahkan penundaan 2 detik di dalam salah satu tool, dan buat
descriptiondua tool lain menjadi mirip sehingga sulit dibedakan - Jalankan lagi lima pertanyaan yang sama, dan temukan kedua masalah itu dari trace saja — tanpa melihat kode yang kamu ubah
- Tambahkan
requestContextKeysuntukuserId, jalankan dengan dua nilai berbeda, dan pastikan kamu bisa memfilter trace per pengguna - Periksa apakah ada data yang tersensor di trace, dan cari tahu field mana
Checklist penerimaan:
- [ ] Kamu bisa membaca hierarki span dan menjelaskan urutan eksekusinya
- [ ] Penundaan 2 detik terlihat jelas sebagai span yang menonjol
- [ ] Kamu bisa menunjukkan dari trace bahwa tool yang salah dipanggil — dengan melihat argumennya, bukan hanya jawabannya
- [ ] Trace bisa difilter berdasarkan
userId - [ ] Kamu bisa menyebutkan minimal satu field yang tersensor otomatis
- [ ] Kamu bisa menyebutkan satu jenis span yang akan kamu buang di produksi, beserta alasannya
Petunjuk: Langkah 5 adalah inti latihan ini, dan lebih sulit dari kelihatannya. Kamu tahu masalahnya karena kamu yang menanamnya — tantangannya adalah menemukan jejaknya di trace, karena begitulah kondisi sebenarnya saat bug datang dari orang lain. Untuk masalah deskripsi tool yang mirip, jejaknya bukan di durasi, melainkan di argumen dan nama tool yang dipilih.
Ikhtisar
- Trace merekam tiap operasi sebagai span yang tersusun hierarkis — membuka kotak hitam loop agent.
- Aktifkan dengan
observability: new Observability({ ... })dari@mastra/observability— properti ini menerima instance, bukan objek konfigurasi.default: { enabled: true }untuk cepat,configsuntuk kendali penuh. requestContextKeysmengambil nilai sepertiuserIddantenantIdsebagai metadata — inilah yang membuat trace bisa dicari di produksi.- Tiga tuas pengurang biaya, diterapkan berurutan:
excludeSpanTypes→spanOutputProcessors→spanFilter. Sampling default-nyaALWAYS. - Pola produksi yang baik: simpan semua trace gagal, sebagian kecil trace sukses.
sensitiveDataFiltermenyala secara default. Sesuaikan field-nya kalau perlu, tapi berpikirlah dua kali sebelum mematikannya.- Trace bisa diperiksa lewat Studio maupun
npx mastra api trace list.
Lanjut ke mana
Trace memperlihatkan struktur eksekusi. Untuk detail di dalam tiap langkah — dan untuk angka agregat lintas ribuan permintaan — kamu butuh dua hal lain: 8.2 Logging & Metrics.