Skip to content

Instantly share code, notes, and snippets.

@angristan
Last active January 3, 2025 20:07
Show Gist options
  • Save angristan/9139b26a390a9ae236e5fe711ae58ec7 to your computer and use it in GitHub Desktop.
Save angristan/9139b26a390a9ae236e5fe711ae58ec7 to your computer and use it in GitHub Desktop.
package main
import (
"database/sql"
"fmt"
"log"
"math/rand"
"os"
"time"
"github.com/getsentry/sentry-go"
sentryotel "github.com/getsentry/sentry-go/otel"
"github.com/gin-gonic/gin"
_ "github.com/lib/pq"
"github.com/redis/go-redis/extra/redisotel/v9"
"github.com/redis/go-redis/v9"
"go.nhat.io/otelsql"
"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
"go.opentelemetry.io/otel"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)
type User struct {
Email string `json:"email"`
}
type Response struct {
Email string `json:"email"`
RedisKey string `json:"redis_key"`
RedisValue string `json:"redis_value"`
}
func main() {
// Initialize Sentry
err := sentry.Init(sentry.ClientOptions{
Dsn: os.Getenv("SENTRY_DSN"),
EnableTracing: true,
TracesSampleRate: 1.0,
Debug: true,
})
if err != nil {
log.Fatalf("sentry.Init: %s", err)
}
defer sentry.Flush(2 * time.Second)
tp := sdktrace.NewTracerProvider(
sdktrace.WithSpanProcessor(sentryotel.NewSentrySpanProcessor()),
)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(sentryotel.NewSentryPropagator())
// Instrument PostgreSQL with otelsql
driverName, err := otelsql.Register("postgres",
otelsql.AllowRoot(),
otelsql.TraceQueryWithoutArgs(),
otelsql.TraceAll(),
otelsql.TraceRowsClose(),
otelsql.TraceRowsAffected(),
otelsql.WithDatabaseName("my_database"), // Optional.
otelsql.WithSystem(semconv.DBSystemPostgreSQL), // Optional.
)
if err != nil {
log.Fatalf("otelsql.Register: %s", err)
}
// Initialize PostgreSQL connection
db, err := sql.Open(driverName, os.Getenv("DATABASE_URL"))
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Test the database connection
err = db.Ping()
if err != nil {
log.Fatal(err)
}
// Initialize Redis client with tracing
opt, err := redis.ParseURL(os.Getenv("REDIS_URL"))
if err != nil {
log.Fatal(err)
}
rdb := redis.NewClient(opt)
if err := redisotel.InstrumentTracing(rdb); err != nil {
log.Fatalf("Failed to instrument Redis for tracing: %s", err)
}
defer rdb.Close()
// Create a Gin router
r := gin.Default()
r.Use(otelgin.Middleware("GinRedisPostgresService"))
r.GET("/", func(c *gin.Context) {
ctx := c.Request.Context()
// Generate random key and value
randomKey := fmt.Sprintf("key_%d", rand.Int())
randomValue := fmt.Sprintf("value_%d", rand.Int())
// Redis SET with TTL
err := rdb.Set(ctx, randomKey, randomValue, 1*time.Hour).Err()
if err != nil {
sentry.CaptureException(err)
c.JSON(500, gin.H{"error": "Redis SET error"})
return
}
// Redis GET
val, err := rdb.Get(ctx, randomKey).Result()
if err != nil {
sentry.CaptureException(err)
c.JSON(500, gin.H{"error": "Redis GET error"})
return
}
// Query database
var user User
err = db.QueryRowContext(ctx, "SELECT email FROM users WHERE id = 1 LIMIT 1").Scan(&user.Email)
if err != nil {
sentry.CaptureException(err)
c.JSON(500, gin.H{"error": "Database query error"})
return
}
// Prepare response
response := Response{
Email: user.Email,
RedisKey: randomKey,
RedisValue: val,
}
// Send JSON response
c.JSON(200, response)
})
// Start the Gin server
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
log.Printf("Server starting on port %s", port)
if err := r.Run(":" + port); err != nil {
log.Fatal(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment