DEV Community

Vigilmon
Vigilmon

Posted on

How to Monitor gRPC Services with Vigilmon (Health Checks + External Uptime)

gRPC services are fast, efficient, and increasingly common in microservice architectures. But they are harder to monitor than REST APIs — HTTP health check tools do not understand the gRPC wire protocol.

This guide explains how to add uptime monitoring to gRPC services and expose them to external monitors like Vigilmon.

The gRPC Monitoring Challenge

Standard HTTP uptime monitors send GET requests and check for a 200 status code. gRPC uses HTTP/2 with Protobuf encoding — a plain GET to a gRPC endpoint returns a 405 or an unreadable response, not a useful health check.

The solution: expose a separate HTTP health endpoint alongside your gRPC service, or implement the standard gRPC health checking protocol.

Option 1: Add an HTTP Health Endpoint

The simplest approach is to run a lightweight HTTP server on a separate port that exposes a health endpoint:

// Go gRPC server with HTTP health endpoint
package main

import (
    "encoding/json"
    "net"
    "net/http"
    "log"

    "google.golang.org/grpc"
    pb "your-service/proto"
)

func main() {
    // Start gRPC server on port 50051
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    grpcServer := grpc.NewServer()
    pb.RegisterYourServiceServer(grpcServer, &yourServiceImpl{})

    // Start HTTP health server on port 8080
    go func() {
        http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
            w.Header().Set("Content-Type", "application/json")
            json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
        })
        http.ListenAndServe(":8080", nil)
    }()

    log.Printf("gRPC server listening on :50051")
    if err := grpcServer.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}
Enter fullscreen mode Exit fullscreen mode

Then monitor http://your-service:8080/health in Vigilmon.

Option 2: Use gRPC Health Checking Protocol

The gRPC ecosystem has a standard health checking protocol. Implement it in your service:

import (
    "google.golang.org/grpc/health"
    "google.golang.org/grpc/health/grpc_health_v1"
)

healthServer := health.NewServer()
grpc_health_v1.RegisterHealthServer(grpcServer, healthServer)

// Set service status
healthServer.SetServingStatus("your.service.YourService", grpc_health_v1.HealthCheckResponse_SERVING)
Enter fullscreen mode Exit fullscreen mode

You can then use grpc-health-probe to check health from your infrastructure, but for external monitoring from Vigilmon, the HTTP endpoint approach is simpler.

Option 3: Envoy Proxy Health Endpoint

If your gRPC services run behind Envoy (common in service meshes), Envoy exposes an admin endpoint you can monitor:

GET http://your-envoy:9901/ready
Enter fullscreen mode Exit fullscreen mode

This confirms Envoy is ready to proxy traffic. Add it to Vigilmon to know when your proxy layer is healthy.

Setting Up Vigilmon for gRPC Services

  1. Sign up at vigilmon.online — free for 50 monitors
  2. Add your HTTP health endpoint URL: https://your-grpc-service.com/health
  3. Set check interval to 1 minute
  4. Configure Slack or email alerts

Monitoring gRPC Deployments on Kubernetes

In Kubernetes, add both liveness and readiness probes alongside Vigilmon:

livenessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 15
  periodSeconds: 10
readinessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5
Enter fullscreen mode Exit fullscreen mode

Kubernetes probes restart unhealthy pods. Vigilmon tells you when the entire service is unreachable from the outside — which can happen even when all pods show healthy internally.

Python gRPC Example

For Python gRPC services, add a Flask health server:

from concurrent import futures
import threading
import grpc
from flask import Flask, jsonify
import your_service_pb2_grpc

app = Flask(__name__)

@app.route('/health')
def health():
    return jsonify({"status": "ok"})

def serve_grpc():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    your_service_pb2_grpc.add_YourServiceServicer_to_server(YourServiceServicer(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    server.wait_for_termination()

if __name__ == '__main__':
    # Start gRPC in background thread
    grpc_thread = threading.Thread(target=serve_grpc, daemon=True)
    grpc_thread.start()

    # Flask HTTP health server on port 8080
    app.run(host='0.0.0.0', port=8080)
Enter fullscreen mode Exit fullscreen mode

What External gRPC Monitoring Catches

External uptime monitoring of gRPC services catches:

  • Network-level failures (DNS, routing, firewall changes)
  • Load balancer misconfiguration
  • Service mesh failures (Envoy crashes, Istio policy changes)
  • Deployment failures where a new image does not start correctly
  • Certificate expiry (if using mTLS on your gRPC connections)

Without external monitoring, gRPC service failures can go undetected until a downstream service starts throwing errors or users notice a degraded feature.

Summary

gRPC services need uptime monitoring as much as REST APIs do — perhaps more, because failures are less visible. Add an HTTP health endpoint to your gRPC services, expose it on a separate port, and add it to Vigilmon for external multi-region monitoring.

Add your gRPC health endpoint to Vigilmon — free, 1-minute check intervals, multi-region.

Top comments (1)

Collapse
 
topstar_ai profile image
Luis Cruz

I found the discussion on implementing the standard gRPC health checking protocol particularly interesting, as it highlights the importance of using established protocols for interoperability. The example code for setting up a health server using health.NewServer() and registering it with the gRPC server is helpful. However, I've found that in some cases, using a separate HTTP health endpoint can be more straightforward, especially when dealing with external monitors like Vigilmon. Have you considered any trade-offs between using the gRPC health checking protocol versus a separate HTTP endpoint in terms of complexity and maintainability?