Tampilan
8.2 Logging & Metrics
Tujuan bab
Setelah bab ini kamu bisa:
- Mengonfigurasi
PinoLoggerdan memilih level yang tepat - Menjelaskan bagaimana log otomatis terkorelasi dengan trace
- Menghasilkan log JSON yang bisa diurai mesin
- Mencatat log terstruktur dari dalam tool lewat
observe - Membedakan kapan memakai log, trace, dan metrik
Prasyarat
Tiga alat, tiga pertanyaan
Trace, log, dan metrik sering disebut bersama sampai batas antaranya kabur. Pembedanya sederhana:
| Alat | Menjawab | Bentuk | Volume |
|---|---|---|---|
| Trace | Apa yang terjadi pada satu permintaan? | Hierarki span | Satu per permintaan |
| Log | Detail apa yang terjadi di dalam satu langkah? | Baris peristiwa | Banyak per permintaan |
| Metrik | Bagaimana perilakunya secara agregat? | Angka teragregasi | Satu angka untuk ribuan permintaan |
Urutan pemakaian yang lazim saat mendiagnosis: metrik memberitahu ada masalah, trace memberitahu di mana, log memberitahu kenapa.
Mengonfigurasi logger
PinoLogger sudah disertakan secara default saat kamu membuat proyek Mastra lewat CLI:
ts
// src/mastra/index.ts
import { Mastra } from '@mastra/core/mastra'
import { PinoLogger } from '@mastra/loggers'
export const mastra = new Mastra({
logger: new PinoLogger({
name: 'Mastra',
level: 'info',
}),
})Level yang tersedia mengikuti konvensi umum: debug, info, warn, error. Untuk pengembangan, debug berguna; untuk produksi, info biasanya titik awal yang wajar.
Log otomatis masuk ke observability
Ini perilaku yang layak diketahui karena menghemat pekerjaan.
Saat observability dikonfigurasi, semua pemanggilan logger otomatis diteruskan ke storage observability-mu. Setiap debug, info, warn, error, dan trackException — dari aplikasimu maupun dari komponen internal Mastra — tersimpan berdampingan dengan trace.
Dokumentasi menegaskan: tidak ada perubahan kode yang diperlukan.
Cara kerjanya berbeda tergantung logger:
- Logger dengan dukungan adapter (
PinoLoggerdanConsoleLogger) menulis ke tujuan mereka sendiri, lalu menurunkan log yang diekspor dari catatan yang sama - Logger kustom tanpa dukungan adapter dibungkus, sehingga menulis ke logger asli dan ke sistem observability sekaligus
Korelasi trace dan log
Ini fitur yang menyelesaikan masalah nyata dan sering luput.
Saat sebuah pemanggilan log terjadi di dalam operasi yang di-trace — run agent, langkah workflow, atau pemanggilan tool — Mastra menyisipkan trace_id dan span_id ke dalam keluaran native logger.
Field itu memakai format W3C trace context dan cocok dengan trace yang terlihat di Studio. Artinya kamu bisa mengambil satu baris log dari stdout dan langsung menemukan trace-nya.
Baris log di stdout Trace di Studio
{ ┌──────────────────┐
"level": "error", ────────▶ │ Trace abc123... │
"msg": "gagal ambil data", │ └── Tool: fetch │
"trace_id": "abc123...", │ ← span ini │
"span_id": "def456..." └──────────────────┘
}Tanpa korelasi ini, mendiagnosis error di produksi berarti mencocokkan timestamp secara manual — pekerjaan yang menjengkelkan dan sering keliru.
Log JSON untuk mesin
Pretty printing menyala secara default dan menghasilkan teks yang enak dibaca manusia. Untuk keluaran JSON yang bisa diurai mesin, matikan:
ts
// src/mastra/index.ts
import { Mastra } from '@mastra/core/mastra'
import { PinoLogger } from '@mastra/loggers'
export const mastra = new Mastra({
logger: new PinoLogger({
name: 'Mastra',
level: 'info',
prettyPrint: false,
}),
})Aturan praktisnya: prettyPrint: true di lokal, false di produksi. Sistem pengumpul log di produksi mengurai JSON; manusia yang menatap terminal tidak.
Mencatat dari dalam tool
Ingat dari 2.1 bahwa parameter kedua execute berisi konteks eksekusi. Salah satu isinya adalah observe, yang menyediakan pembantu observability.
ts
// src/mastra/tools/data-tool.ts
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'
export const dataTool = createTool({
id: 'ambil-data',
description: 'Ambil data penjualan untuk satu periode',
inputSchema: z.object({ periode: z.string() }),
outputSchema: z.object({ jumlah: z.number() }),
execute: async ({ periode }, { observe }) => {
observe.log('info', 'mulai ambil data', { periode })
const jumlah = await observe.span('hitung-penjualan', async () => {
return 42
})
observe.log('info', 'data diterima', { periode, jumlah })
return { jumlah }
},
})observe.log adalah fungsi, bukan objek
Perhatikan bentuk pemanggilannya: observe.log('info', pesan, data) — level adalah argumen pertama.
Bentuk observe.log.info(...) yang terlihat wajar dan mengikuti kebiasaan pustaka logging lain akan ditolak compiler:
Property 'info' does not exist on type
'(level: "debug" | "info" | "warn" | "error" | "fatal",
message: string, data?: Record<string, unknown>) => void'Pesan error itu sekaligus memberitahu kelima level yang tersedia — perhatikan ada fatal, yang tidak ada pada level PinoLogger di bagian sebelumnya.
Dua kemampuan yang disediakan observe:
| Kegunaan | |
|---|---|
observe.log(level, pesan, data?) | Mencatat log terstruktur yang terkorelasi dengan trace |
observe.span(nama, fn) | Membungkus sebagian pekerjaan sebagai span anak |
observe.span() berguna saat sebuah tool melakukan beberapa hal berbeda dan kamu ingin melihat masing-masing terpisah di trace — bukan satu span besar tanpa rincian.
Dokumentasi mencatat bahwa observe selalu tersedia — saat tidak ada konteks tracing yang aktif, span menjalankan fungsinya secara langsung dan log menjadi no-op. Artinya kamu tidak perlu memeriksa keberadaannya sebelum memakainya.
Manfaat memakai observe.log alih-alih console.log: log-nya terkorelasi dengan trace secara otomatis, dan ikut tersimpan di storage observability.
Catat data terstruktur, bukan kalimat
observe.log('info', 'data diterima', { periode, jumlah }) jauh lebih berguna daripada menggabungkan nilainya ke dalam string pesan. Yang pertama bisa difilter dan diagregasi; yang kedua hanya bisa dibaca.
Metrik
Metrik menjawab pertanyaan agregat yang tidak bisa dijawab satu trace: berapa rata-rata latensi minggu ini, berapa persen permintaan yang gagal, berapa token yang dipakai per pengguna.
Perbedaan mendasarnya dari trace: trace bagus untuk satu kejadian, metrik bagus untuk pola lintas ribuan kejadian. Kamu tidak akan menemukan bahwa latensi naik 30% sejak deployment kemarin dengan membaca trace satu per satu.
Seperti trace dan log, metrik disimpan di storage observability-mu dan bisa dilihat di Studio maupun lewat CLI.
Memeriksa dari baris perintah
bash
npx mastra api log list '{"level":"error","page":0,"perPage":50}'Perintah ini mengambil log error terbaru tanpa membuka Studio. Ia memerlukan server Mastra yang berjalan dengan observability logging terkonfigurasi.
Untuk mengetahui bentuk filter yang tersedia:
bash
npx mastra api log list --schemaPola --schema ini berlaku untuk perintah mastra api lainnya juga, dan berguna saat kamu tidak ingat bentuk argumen yang diminta.
Memilih alat yang tepat
Kesalahan umum
Gejala: Log di produksi sulit dicari dan tidak bisa difilter dengan perkakas pengumpul log. Penyebab: prettyPrint masih pada nilai bawaan true, sehingga keluarannya teks bebas alih-alih JSON. Perbaikan: Setel prettyPrint: false di produksi. Simpan true hanya untuk pengembangan lokal.
Gejala: Ada baris log error di stdout, tapi kamu tidak bisa menemukan trace yang bersangkutan di Studio. Penyebab: Log dihasilkan oleh console.log biasa alih-alih logger Mastra atau observe.log, sehingga trace_id dan span_id tidak ikut disisipkan. Perbaikan: Pakai logger Mastra di tingkat aplikasi, dan observe.log di dalam tool. Keduanya otomatis membawa konteks trace.
Coba sendiri
Tantangan: Bangun jalur diagnosis lengkap dari metrik ke log, lalu buktikan korelasi trace bekerja.
Ketentuan:
- Konfigurasikan
PinoLoggerdenganprettyPrint: falsedan levelinfo - Tambahkan
observe.log.info()di awal dan akhir tiap tool pada agent-mu, dengan data terstruktur, bukan kalimat yang digabung - Tambahkan satu tool yang gagal secara acak sekitar sepertiga waktu, dan catat kegagalannya dengan
observe.log.error()beserta konteksnya - Jalankan agent 15 kali dengan pertanyaan yang bervariasi
- Ambil satu baris log error dari stdout, salin
trace_id-nya, dan temukan trace itu di Studio - Jalankan
npx mastra api log listdengan filter level error, dan bandingkan dengan apa yang kamu lihat di stdout - Ubah satu
observe.logmenjadiconsole.logbiasa, jalankan lagi, dan perhatikan apa yang hilang
Checklist penerimaan:
- [ ] Keluaran stdout berupa JSON yang memuat
trace_iddanspan_id - [ ] Kamu berhasil melompat dari satu baris log ke trace-nya di Studio
- [ ]
mastra api log listmengembalikan error yang sama dengan yang kamu lihat di stdout - [ ] Log dari langkah 7 tidak membawa
trace_id, dan kamu bisa menjelaskan kenapa itu masalah - [ ] Semua log-mu memakai data terstruktur — tidak ada yang menggabung nilai ke dalam string pesan
- [ ] Kamu bisa menjelaskan kapan kamu akan melihat metrik alih-alih trace
Petunjuk: Langkah 7 memperlihatkan nilai korelasi dengan cara yang paling meyakinkan: dengan menghilangkannya. Satu baris log tanpa trace_id di antara ratusan baris lain praktis adalah petunjuk buntu — kamu tahu ada yang gagal, tapi tidak tahu pada permintaan yang mana.
Ikhtisar
- Trace untuk satu permintaan, log untuk detail di dalam langkah, metrik untuk pola agregat. Diagnosis biasanya berjalan: metrik → trace → log.
PinoLoggerdisertakan default oleh CLI. Level:debug,info,warn,error.- Log otomatis diteruskan ke storage observability saat observability dikonfigurasi — tanpa perubahan kode.
- Log di dalam operasi yang di-trace otomatis membawa
trace_iddanspan_iddalam format W3C, sehingga bisa dilompati langsung ke trace-nya. prettyPrint: falseuntuk produksi agar keluarannya JSON yang bisa diurai mesin.- Di dalam tool, pakai
observe.log(level, pesan, data)dari parameter keduaexecute— ia fungsi, bukan objek, jadiobserve.log.info(...)tidak akan kompilasi. Tersedia jugaobserve.span(nama, fn)untuk membuat span anak. Keduanya selalu ada, dan menjadi no-op saat tidak ada tracing aktif. - Catat data terstruktur, bukan nilai yang digabung ke dalam kalimat.
- CLI:
npx mastra api log list, dan--schemauntuk melihat bentuk filter.
Lanjut ke mana
Kamu sekarang bisa melihat apa yang terjadi. Dua bab terakhir bagian ini tentang menilai hasilnya: 8.3 Scorers Bawaan.