Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
3.4 kB ยท 139 lines
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140package server
import ( "context" "fmt" "log/slog" "net/http" "os" "strconv" "time"
"github.com/google/uuid" "github.com/jmoiron/sqlx" _ "github.com/joho/godotenv/autoload" "go.opentelemetry.io/contrib/bridges/otelslog" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp" "go.opentelemetry.io/otel/log/global" sdklog "go.opentelemetry.io/otel/sdk/log" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
"github.com/openstatushq/openstatus/apps/private-location/internal/database")
type Server struct { port int db *sqlx.DB logger *slog.Logger logProvider *sdklog.LoggerProvider}
// instanceID is generated once at startupvar instanceID = uuid.New().String()
// NewServer returns an HTTP server and a cleanup function to shutdown the log provider.func NewServer() (*http.Server, func(context.Context)) { portStr := os.Getenv("PORT") if portStr == "" { portStr = "8080" } port, err := strconv.Atoi(portStr) if err != nil { fmt.Fprintf(os.Stderr, "invalid PORT value %q: %v\n", portStr, err) os.Exit(1) }
logger, logProvider := setupLogger()
newServer := &Server{ port: port, db: database.New(), logger: logger, logProvider: logProvider, }
// Declare Server config server := &http.Server{ Addr: fmt.Sprintf(":%d", newServer.port), Handler: newServer.RegisterRoutes(), IdleTimeout: time.Minute, ReadTimeout: 10 * time.Second, WriteTimeout: 30 * time.Second, }
// Startup logging slog.Info("server starting", "port", port, "instance_id", instanceID, "axiom_configured", os.Getenv("AXIOM_TOKEN") != "", "tinybird_configured", os.Getenv("TINYBIRD_TOKEN") != "", )
// Return cleanup function for graceful shutdown cleanup := func(ctx context.Context) { if logProvider != nil { logProvider.Shutdown(ctx) } database.Close() }
return server, cleanup}
func setupLogger() (*slog.Logger, *sdklog.LoggerProvider) { ctx := context.Background()
axiomToken := env("AXIOM_TOKEN", "") axiomDataset := env("AXIOM_DATASET", "dev")
// If no Axiom token, return a standard logger if axiomToken == "" { logger := slog.Default() return logger, nil }
environment := env("ENVIRONMENT", "production")
res := resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String("openstatus-private-location"), attribute.String("environment", environment),
attribute.String("instance_id", instanceID), )
// Set up OTLP log exporter for Axiom exporter, err := otlploghttp.New(ctx, otlploghttp.WithEndpointURL("https://eu-central-1.aws.edge.axiom.co/v1/logs"), otlploghttp.WithHeaders(map[string]string{ "Authorization": "Bearer " + axiomToken, "X-Axiom-Dataset": axiomDataset, }), ) if err != nil { fmt.Fprintf(os.Stderr, "failed to create OTLP exporter: %v\n", err) return slog.Default(), nil }
// Create log provider with resource and batch processor logProvider := sdklog.NewLoggerProvider( sdklog.WithResource(res), sdklog.WithProcessor(sdklog.NewBatchProcessor(exporter)), )
global.SetLoggerProvider(logProvider) logger := otelslog.NewLogger("openstatus-private-location") slog.SetDefault(logger)
return logger, logProvider}
func env(key, fallback string) string { if value, ok := os.LookupEnv(key); ok { return value } return fallback}