Openstatus www.openstatus.dev
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 258 lines 6.9 kB view raw
1package otel 2 3import ( 4 "context" 5 "errors" 6 "fmt" 7 "time" 8 9 "github.com/openstatushq/openstatus/apps/checker/checker" 10 "github.com/openstatushq/openstatus/apps/checker/request" 11 "github.com/rs/zerolog/log" 12 13 "go.opentelemetry.io/otel" 14 "go.opentelemetry.io/otel/attribute" 15 "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" 16 "go.opentelemetry.io/otel/metric" 17 sdkMetrics "go.opentelemetry.io/otel/sdk/metric" 18 "go.opentelemetry.io/otel/sdk/resource" 19 20 semconv "go.opentelemetry.io/otel/semconv/v1.26.0" 21) 22 23func SetupOTelSDK( 24 ctx context.Context, url string, probes string, headers map[string]string, 25) (shutdown func(context.Context) error, err error) { 26 var shutdownFuncs []func(context.Context) error 27 28 shutdown = func(ctx context.Context) error { 29 var err error 30 31 for _, fn := range shutdownFuncs { 32 err = errors.Join(err, fn(ctx)) 33 } 34 35 shutdownFuncs = nil 36 37 return err 38 } 39 40 handleErr := func(inErr error) { 41 err = errors.Join(inErr, shutdown(ctx)) 42 } 43 44 res, err := newResource() 45 if err != nil { 46 handleErr(err) 47 48 return nil, err 49 } 50 51 meterProvider, err := newMeterProvider(ctx, res, url, headers) 52 if err != nil { 53 handleErr(err) 54 55 return nil, err 56 } 57 58 shutdownFuncs = append(shutdownFuncs, meterProvider.Shutdown) 59 60 otel.SetMeterProvider(meterProvider) 61 62 return shutdown, nil 63} 64 65func newResource() (*resource.Resource, error) { 66 return resource.Merge(resource.Default(), 67 resource.NewWithAttributes(semconv.SchemaURL, 68 semconv.ServiceName("openstatus-synthetic-check"), 69 semconv.ServiceVersion("0.1.0"), 70 )) 71} 72 73func newMeterProvider( 74 ctx context.Context, 75 res *resource.Resource, 76 url string, 77 headers map[string]string, 78) (*sdkMetrics.MeterProvider, error) { 79 80 grafanaExporter, err := otlpmetrichttp.New(ctx, 81 otlpmetrichttp.WithEndpointURL(url), 82 // otlpmetrichttp.WithInsecure(), 83 otlpmetrichttp.WithHeaders(headers), 84 ) 85 if err != nil { 86 return nil, err 87 } 88 89 meterProvider := sdkMetrics.NewMeterProvider( 90 sdkMetrics.WithResource(res), 91 92 sdkMetrics.WithReader(sdkMetrics.NewPeriodicReader(grafanaExporter, 93 sdkMetrics.WithInterval(3*time.Second))), 94 ) 95 96 return meterProvider, nil 97} 98 99func RecordHTTPMetrics(ctx context.Context, req request.HttpCheckerRequest, result checker.Response, region string) { 100 101 otelShutdown, err := SetupOTelSDK(ctx, req.OtelConfig.Endpoint, region, req.OtelConfig.Headers) 102 103 if err != nil { 104 log.Ctx(ctx).Error().Err(err).Msg("Error setting up otel") 105 } 106 107 defer func() { 108 err = errors.Join(err, otelShutdown(ctx)) 109 if err != nil { 110 log.Ctx(ctx).Error().Err(err).Msg("Error sending the data") 111 } 112 }() 113 114 meter := otel.Meter("OpenStatus") 115 116 if result.Error != "" { 117 att := metric.WithAttributes( 118 attribute.String("openstatus.probes", region), 119 attribute.String("openstatus.target", req.URL), 120 semconv.HTTPResponseStatusCode(result.Status), 121 ) 122 statusError, err := meter.Int64Counter("openstatus.error", metric.WithDescription("Status of the check")) 123 124 if err != nil { 125 log.Ctx(ctx).Error().Err(err).Msg("Error setting up counter") 126 } 127 128 statusError.Add(ctx, (1), att) 129 130 return 131 } 132 133 att := metric.WithAttributes( 134 attribute.String("openstatus.probes", region), 135 attribute.String("openstatus.target", req.URL), 136 semconv.HTTPResponseStatusCode(result.Status), 137 ) 138 139 status, err := meter.Int64Counter("openstatus.status", metric.WithDescription("Status of the check")) 140 141 if err != nil { 142 log.Ctx(ctx).Error().Err(err).Msg("Error setting up conunter") 143 } 144 145 status.Add(ctx, 1, att) 146 147 gauge, err := meter.Float64Gauge("openstatus.http.request.duration", 148 metric.WithDescription("Duration of the check"), metric.WithUnit("ms")) 149 150 if err != nil { 151 fmt.Println("Error creating gauge", err) 152 } 153 154 gauge.Record(ctx, float64(result.Latency), att) 155 156 gaugeDns, err := meter.Float64Gauge("openstatus.http.dns.duration", 157 metric.WithDescription("Duration of the dns lookup"), metric.WithUnit("ms")) 158 159 if err != nil { 160 fmt.Println("Error creating gauge", err) 161 } 162 163 gaugeDns.Record(ctx, float64(result.Timing.DnsDone-result.Timing.DnsStart), att) 164 165 gaugeConnect, err := meter.Float64Gauge("openstatus.http.connection.duration", 166 metric.WithDescription("Duration of the connection"), metric.WithUnit("ms")) 167 168 if err != nil { 169 fmt.Println("Error creating gauge", err) 170 } 171 172 gaugeConnect.Record(ctx, float64(result.Timing.ConnectDone-result.Timing.ConnectStart), att) 173 174 gaugeTLS, err := meter.Float64Gauge("openstatus.http.tls.duration", 175 metric.WithDescription("Duration of the tls handshake"), metric.WithUnit("ms")) 176 177 if err != nil { 178 fmt.Println("Error creating gauge", err) 179 } 180 181 gaugeTLS.Record(ctx, float64(result.Timing.TlsHandshakeDone-result.Timing.TlsHandshakeStart), att) 182 183 gaugeTTFB, err := meter.Float64Gauge("openstatus.http.ttfb.duration", 184 metric.WithDescription("Duration of the ttfb"), metric.WithUnit("ms")) 185 186 if err != nil { 187 fmt.Println("Error creating gauge", err) 188 } 189 190 gaugeTTFB.Record(ctx, float64(result.Timing.FirstByteDone-result.Timing.FirstByteStart), att) 191 192 gaugeTransfer, err := meter.Float64Gauge("openstatus.http.transfer.duration", 193 metric.WithDescription("Duration of the transfer"), metric.WithUnit("ms")) 194 195 if err != nil { 196 fmt.Println("Error creating gauge", err) 197 } 198 199 gaugeTransfer.Record(ctx, float64(result.Timing.TransferDone-result.Timing.TransferStart), att) 200} 201 202func RecordTCPMetrics(ctx context.Context, req request.TCPCheckerRequest, result checker.TCPResponse, region string) { 203 204 otelShutdown, err := SetupOTelSDK(ctx, req.OtelConfig.Endpoint, region, req.OtelConfig.Headers) 205 206 if err != nil { 207 log.Ctx(ctx).Error().Err(err).Msg("Error setting up otel") 208 } 209 210 defer func() { 211 err = errors.Join(err, otelShutdown(ctx)) 212 if err != nil { 213 log.Ctx(ctx).Error().Err(err).Msg("Error sending the data") 214 } 215 }() 216 217 meter := otel.Meter("OpenStatus") 218 219 if result.Error == 1 { 220 att := metric.WithAttributes( 221 attribute.String("openstatus.probes", region), 222 attribute.String("openstatus.target", req.URI), 223 ) 224 statusError, err := meter.Int64Counter("openstatus.error", metric.WithDescription("Status of the check")) 225 226 if err != nil { 227 log.Ctx(ctx).Error().Err(err).Msg("Error setting up counter") 228 } 229 230 statusError.Add(ctx, (1), att) 231 232 return 233 } 234 235 att := metric.WithAttributes( 236 attribute.String("openstatus.probes", region), 237 attribute.String("openstatus.target", req.URI), 238 ) 239 240 gauge, err := meter.Float64Gauge("openstatus.tcp.request.duration", 241 metric.WithDescription("Duration of the check"), metric.WithUnit("ms")) 242 243 if err != nil { 244 fmt.Println("Error creating gauge", err) 245 } 246 247 gauge.Record(ctx, float64(result.Latency), att) 248 249 gaugeTCP, err := meter.Float64Gauge("openstatus.tcp.tcp.duration", 250 metric.WithDescription("Duration of the dns lookup"), metric.WithUnit("ms")) 251 252 if err != nil { 253 fmt.Println("Error creating gauge", err) 254 } 255 256 gaugeTCP.Record(ctx, float64(result.Timing.TCPDone-result.Timing.TCPStart), att) 257 258}