# gRPC

> Instrument gRPC Go applications with the Last9 Go Agent for automatic RPC tracing and metrics

Source: https://last9.io/docs/integrations/frameworks/go/grpc/

Use the Last9 Go Agent to instrument your gRPC application with automatic tracing and metrics. The agent wraps `otelgrpc` — full OTel compliance for both unary and streaming RPCs with minimal code changes.

## Prerequisites

- Go 1.22 or higher
- gRPC (`google.golang.org/grpc`)
- Last9 account with OTLP credentials

## Installation

1. **Install the Last9 Go Agent**

   ```bash
   go get github.com/last9/go-agent
   ```

2. **Set Environment Variables**

   ```bash
   export OTEL_SERVICE_NAME="your-grpc-service"
   export OTEL_EXPORTER_OTLP_ENDPOINT="$last9_otlp_endpoint"
   export OTEL_EXPORTER_OTLP_HEADERS="Authorization=$last9_otlp_auth_header"
   export OTEL_TRACES_SAMPLER="always_on"
   export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=production"
   ```

3. **Instrument your application**

**Server**

   Replace `grpc.NewServer()` with `grpcagent.NewServer()` — it returns a `*grpc.Server` with OpenTelemetry tracing already configured for all unary and streaming RPCs:

   ```go
   package main

   import (
       "log"
       "net"

       agent "github.com/last9/go-agent"
       grpcagent "github.com/last9/go-agent/instrumentation/grpc"
       pb "your-module/proto"
   )

   func main() {
       if err := agent.Start(); err != nil {
           log.Fatalf("failed to start agent: %v", err)
       }
       defer agent.Shutdown()

       lis, err := net.Listen("tcp", ":50051")
       if err != nil {
           log.Fatalf("failed to listen: %v", err)
       }

       s := grpcagent.NewServer() // drop-in for grpc.NewServer()
       pb.RegisterYourServiceServer(s, &server{})
       s.Serve(lis)
   }
   ```

**Client**

   Pass `grpcagent.NewClientDialOption()` when dialing to automatically trace all outgoing RPCs:

   ```go
   package main

   import (
       "log"

       agent "github.com/last9/go-agent"
       grpcagent "github.com/last9/go-agent/instrumentation/grpc"
       pb "your-module/proto"
       "google.golang.org/grpc"
       "google.golang.org/grpc/credentials/insecure"
   )

   func main() {
       if err := agent.Start(); err != nil {
           log.Fatalf("failed to start agent: %v", err)
       }
       defer agent.Shutdown()

       conn, err := grpc.NewClient(
           "localhost:50051",
           grpc.WithTransportCredentials(insecure.NewCredentials()),
           grpcagent.NewClientDialOption(), // automatic OTel client tracing
       )
       if err != nil {
           log.Fatalf("did not connect: %v", err)
       }
       defer conn.Close()

       c := pb.NewYourServiceClient(conn)
       // make RPC calls normally — all are traced
   }
   ```

   :::tip
   Set a different `OTEL_SERVICE_NAME` for the server and client so their spans are distinguishable in Last9.
   :::

## Database Instrumentation

Use the agent's database integration for automatic SQL query tracing. Supported drivers: PostgreSQL, MySQL, SQLite.

```go
import (
    "log"
    "os"

    "github.com/last9/go-agent/integrations/database"
)

var db *sql.DB

func init() {
    var err error
    db, err = database.Open(database.Config{
        DriverName:   "postgres",
        DSN:          os.Getenv("DATABASE_URL"),
        DatabaseName: "mydb",
    })
    if err != nil {
        log.Fatal(err)
    }
}

// Pass ctx from the RPC handler to propagate the trace
func (s *server) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) {
    rows, err := db.QueryContext(ctx, "SELECT id, name FROM users WHERE id = $1", req.Id)
    // ...
}
```

## Redis Instrumentation

```go
import redisagent "github.com/last9/go-agent/integrations/redis"

// Drop-in replacement for redis.NewClient()
rdb := redisagent.NewClient(&redis.Options{
    Addr: "localhost:6379",
})

func (s *server) GetFromCache(ctx context.Context, req *pb.CacheRequest) (*pb.CacheResponse, error) {
    val, err := rdb.Get(ctx, req.Key).Result()
    // ...
}
```

## HTTP Client Instrumentation

For outgoing HTTP requests within RPC handlers with automatic `traceparent` propagation:

```go
import httpagent "github.com/last9/go-agent/integrations/http"

client := httpagent.NewClient(&http.Client{})

func (s *server) CallUpstream(ctx context.Context, req *pb.UpstreamRequest) (*pb.UpstreamResponse, error) {
    httpReq, _ := http.NewRequestWithContext(ctx, "GET", "https://api.example.com/data", nil)
    resp, err := client.Do(httpReq)
    // ...
}
```

## What Gets Traced Automatically

| Signal  | What's captured                                                 |
| ------- | --------------------------------------------------------------- |
| Traces  | Every RPC: method, service, status code, latency                |
| Traces  | Streaming RPCs: message count, stream lifecycle                 |
| Traces  | Database queries: SQL statement, db system, server address/port |
| Traces  | Redis commands: command name, key                               |
| Traces  | Outbound HTTP: method, URL, status code                         |
| Metrics | Runtime: memory, GC pause, goroutine count                      |
| Metrics | Database: connection pool usage, idle, wait time                |

## View Traces and Metrics

After running your application, navigate to [Trace Explorer](https://app.last9.io/traces) and [Metrics Explorer](https://app.last9.io/metrics) in Last9 to view your telemetry data.

---

## Troubleshooting

Please get in touch with us on [Discord](https://discord.com/invite/Q3p2EEucx9) or [Email](mailto:support@last9.io) if you have any questions.
