Ketika membangun aplikasi backend modern, salah satu elemen penting namun sering diabaikan adalah logging. Logging bukan hanya tentang menuliskan error ke file log — ia adalah jendela kehidupan aplikasi kita: Apakah ada yang error? Endpoint mana yang sering diakses? Berapa lama waktu eksekusi tiap permintaan? Apalagi, jika kita menggunakan gRPC yang komunikasinya berbasis protokol biner dan streaming, log yang baik dapat sangat membantu debugging dan pemantauan.
Pada artikel ini, kita akan membahas bagaimana cara menambahkan logging sederhana pada server gRPC menggunakan bahasa pemrograman Go. Kita juga akan membahas kapan waktu yang tepat untuk melakukan logging, tipe informasi yang sebaiknya dituliskan, serta contoh kode lengkap dengan simulasi, diagram alur, dan tabel.
Kenapa Logging di gRPC itu Penting?
Sebelum menuju kode, mari kita jabarkan beberapa alasan berikut:
- gRPC menggunakan protokol biner, sehingga pesan request/response tidak dapat diinspeksi dengan mudah via tools HTTP.
- Dengan pipeline intersep (interceptors) di gRPC, developer dapat menambahkan logging tanpa banyak mengubah kode business logic.
- Logging mempermudah troubleshooting dan monitoring, terutama pada microservices yang diskalakan secara horizontal.
Skema Logging di Server gRPC
gRPC menyediakan interceptor yang dapat digunakan untuk mengintersepsi (menyisipkan logika middleware) pada setiap permintaan (request) yang masuk.
Secara sederhana, alurnya adalah sebagai berikut:
flowchart LR A[Request dari Client] --> B[Interceptor Logging] B --> C[Method/Handler gRPC] C --> D[Response Kembali ke Client]
Jadi, logging terjadi sebelum (atau setelah) handler gRPC dijalankan.
Implementasi gRPC Logging di Go
Mari ke daging utama artikel: implementasi sederhana logging pada gRPC server.
1. Setup Proyek Sederhana
Kita asumsikan Anda sudah punya service sederhana, misal layanan HelloService
.
// hello.proto
syntax = "proto3";
package helloworld;
service HelloService {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
Setelah meng-generate kode hasil dari file proto di atas (misal: protoc ...
), mari kita lanjutkan ke implementasi logging.
2. Membuat Interceptor Logging
Interceptor gRPC
Interceptor gRPC di Go adalah fungsi middleware yang mengikuti signature tertentu. UnaryServerInterceptor
umum digunakan untuk RPC biasa (non-streaming). Berikut contoh interceptor logging sederhana:
// logging_interceptor.go
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
)
// Unary interceptor untuk logging request dan response time
func LoggingInterceptor(
ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (resp interface{}, err error) {
start := time.Now()
log.Printf("Received request: %s at %s", info.FullMethod, start.Format(time.RFC3339))
// Eksekusi RPC handler (bisnis logic)
resp, err = handler(ctx, req)
duration := time.Since(start)
if err != nil {
log.Printf("Error on %s: %v (duration: %s)", info.FullMethod, err, duration)
} else {
log.Printf("Completed %s (duration: %s)", info.FullMethod, duration)
}
return resp, err
}
Apa yang dilakukan kode ini?
- Sebelum handler dijalankan, ia mencatat waktu mulai dan nama endpoint RPC yang diakses.
- Setelah handler selesai, ia mencatat waktu selesai (
duration
) dan status sukses atau error.
3. Mengaktifkan Interceptor pada Server
Pada inisialisasi server gRPC, tambahkan interceptor tersebut:
// main.go
import (
"google.golang.org/grpc"
"log"
"net"
)
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
grpcServer := grpc.NewServer(
grpc.UnaryInterceptor(LoggingInterceptor),
)
// Register service anda di sini
helloworld.RegisterHelloServiceServer(grpcServer, &HelloServiceImpl{})
log.Println("Server listening at :50051")
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
Dengan setup seperti ini, setiap request yang datang ke server gRPC Anda akan melewati LoggingInterceptor, dan tercatat ke log Anda.
Contoh Output Log
Jika Anda menjalankan server dan melakukan request, log yang dihasilkan bisa berupa:
2024/07/01 10:15:23 Received request: /helloworld.HelloService/SayHello at 2024-07-01T10:15:23+07:00
2024/07/01 10:15:23 Completed /helloworld.HelloService/SayHello (duration: 102.324µs)
Jika terjadi error pada handler:
2024/07/01 10:15:25 Received request: /helloworld.HelloService/SayHello at 2024-07-01T10:15:25+07:00
2024/07/01 10:15:25 Error on /helloworld.HelloService/SayHello: rpc error: code = NotFound desc = name not found (duration: 98.202µs)
Simulasi: Membandingkan Server dengan & tanpa Logging
Skenario | Server Tanpa Logging | Server Dengan Logging |
---|---|---|
Debugging error RPC | Hanya dapat melihat dari error client | Bisa melihat log error di server, waktu error terjadi, request RPC |
Menganalisis performa | Tidak tahu endpoint lambat/cepat | Dapat melihat durasi tiap request |
Audit request | Tidak tahu siapa yang request, kapan | Muncul riwayat akses di log |
Menambahkan Informasi Tambahan ke Log
Untuk produksi, umumnya info berikut sebaiknya ikut dicatat:
- Request/response ID (trace id, jika ada)
- Metadata user (jika authentication diimplementasi)
- IP address peminta
- Size request/response
- Custom tags
Untuk hal tersebut, bisa dikembangkan misalnya menggunakan library zap
atau logrus
yang mendukung structured logging dan output JSON. Namun untuk artikel kali ini, kita fokus pada logging dasar terlebih dahulu.
Streaming RPC? Bisa, Tapi…
Untuk gRPC streaming, Anda perlu menggunakan StreamServerInterceptor
yang memiliki signature berbeda. Konsepnya sama:
func LoggingStreamInterceptor(
srv interface{},
ss grpc.ServerStream,
info *grpc.StreamServerInfo,
handler grpc.StreamHandler,
) error {
log.Printf("Streaming request: %s", info.FullMethod)
start := time.Now()
err := handler(srv, ss)
if err != nil {
log.Printf("Streaming error on %s: %v (in %s)", info.FullMethod, err, time.Since(start))
} else {
log.Printf("Finished streaming %s (in %s)", info.FullMethod, time.Since(start))
}
return err
}
Dan didaftarkan dengan:
grpc.NewServer(
grpc.StreamInterceptor(LoggingStreamInterceptor),
)
Diagram Alur Logging di gRPC Server
sequenceDiagram participant C as gRPC Client participant I as Logging Interceptor participant S as Service Handler C->>I: Kirim request I->>I: Catat log permintaan (timestamp, method) I->>S: Teruskan ke handler service S-->>I: Jawab/Response dari handler I->>I: Catat log response/error (durasi eksekusi) I->>C: Kirim response
Kesimpulan
Logging di server gRPC itu esensial agar aplikasi bisa diobservasi dan di-debug dengan baik. Dengan memanfaatkan mekanisme interceptor, kita bisa menambah logging dengan cost yang rendah dan nyaris tanpa modifikasi di business logic.
Tentu, produksi membutuhkan logging lebih advanced — termasuk trace ID antar layanan, contextual log, export ke service observability (ELK Stack, Grafana Loki, dll). Namun, mulai dari logging sederhana seperti ini sudah sangat membantu.
Semoga artikel ini membantu Anda meningkatkan observability aplikasi gRPC Anda!
Pingin bahas logging JSON, multi-level logging, atau trace-id di gRPC Go? Drop komentar di bawah! 🚀
13 Implementasi Unary RPC
Artikel Terhangat
13 Implementasi Unary RPC
06 Jun 2025
12 Membuat Client gRPC Pertama Anda
06 Jun 2025
11 Membuat Server gRPC Pertama Anda
06 Jun 2025
9 Meng-Generate Kode Go dari File Protobuf
06 Jun 2025
8 Memahami Sintaks Dasar File Protobuf
06 Jun 2025

13 Implementasi Unary RPC

12 Membuat Client gRPC Pertama Anda

11 Membuat Server gRPC Pertama Anda

9 Meng-Generate Kode Go dari File Protobuf
