Chill, it's not what you think. Helpers and middleware for tracing and metrics provided by OpenTelemetry.
+21
-6
go.mod
+21
-6
go.mod
···
26
26
github.com/sethvargo/go-envconfig v1.1.0
27
27
github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e
28
28
github.com/yuin/goldmark v1.4.13
29
+
go.opentelemetry.io/otel v1.35.0
30
+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0
31
+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0
32
+
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0
33
+
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0
34
+
go.opentelemetry.io/otel/metric v1.35.0
35
+
go.opentelemetry.io/otel/sdk v1.35.0
36
+
go.opentelemetry.io/otel/sdk/metric v1.35.0
37
+
go.opentelemetry.io/otel/trace v1.35.0
29
38
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
30
39
)
31
40
···
39
48
github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect
40
49
github.com/carlmjohnson/versioninfo v0.22.5 // indirect
41
50
github.com/casbin/govaluate v1.3.0 // indirect
51
+
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
42
52
github.com/cespare/xxhash/v2 v2.3.0 // indirect
43
53
github.com/cloudflare/circl v1.6.0 // indirect
44
54
github.com/davecgh/go-spew v1.1.1 // indirect
···
47
57
github.com/felixge/httpsnoop v1.0.4 // indirect
48
58
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
49
59
github.com/go-git/go-billy/v5 v5.6.2 // indirect
50
-
github.com/go-logr/logr v1.4.1 // indirect
60
+
github.com/go-logr/logr v1.4.2 // indirect
51
61
github.com/go-logr/stdr v1.2.2 // indirect
52
62
github.com/goccy/go-json v0.10.2 // indirect
53
63
github.com/gogo/protobuf v1.3.2 // indirect
54
64
github.com/gorilla/css v1.0.1 // indirect
55
65
github.com/gorilla/securecookie v1.1.2 // indirect
56
66
github.com/gorilla/websocket v1.5.1 // indirect
67
+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
57
68
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
58
69
github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
59
70
github.com/hashicorp/golang-lru v1.0.2 // indirect
···
99
110
github.com/xanzy/ssh-agent v0.3.3 // indirect
100
111
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect
101
112
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
113
+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
102
114
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
103
-
go.opentelemetry.io/otel v1.21.0 // indirect
104
-
go.opentelemetry.io/otel/metric v1.21.0 // indirect
105
-
go.opentelemetry.io/otel/trace v1.21.0 // indirect
115
+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
116
+
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
106
117
go.uber.org/atomic v1.11.0 // indirect
107
118
go.uber.org/multierr v1.11.0 // indirect
108
119
go.uber.org/zap v1.26.0 // indirect
109
120
golang.org/x/crypto v0.37.0 // indirect
110
121
golang.org/x/net v0.39.0 // indirect
111
-
golang.org/x/sys v0.32.0 // indirect
122
+
golang.org/x/sys v0.33.0 // indirect
123
+
golang.org/x/text v0.24.0 // indirect
112
124
golang.org/x/time v0.5.0 // indirect
113
-
google.golang.org/protobuf v1.34.2 // indirect
125
+
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
126
+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
127
+
google.golang.org/grpc v1.71.0 // indirect
128
+
google.golang.org/protobuf v1.36.5 // indirect
114
129
gopkg.in/warnings.v0 v0.1.2 // indirect
115
130
gopkg.in/yaml.v3 v3.0.1 // indirect
116
131
lukechampine.com/blake3 v1.2.1 // indirect
+48
-18
go.sum
+48
-18
go.sum
···
42
42
github.com/casbin/govaluate v1.2.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
43
43
github.com/casbin/govaluate v1.3.0 h1:VA0eSY0M2lA86dYd5kPPuNZMUD9QkWnOCnavGrw9myc=
44
44
github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
45
+
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
46
+
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
45
47
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
46
48
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
47
49
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
···
82
84
github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk=
83
85
github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC2MDs4ee8=
84
86
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
85
-
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
86
-
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
87
+
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
88
+
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
87
89
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
88
90
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
89
91
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
···
93
95
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
94
96
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
95
97
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
98
+
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
99
+
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
96
100
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
97
-
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
98
-
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
101
+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
102
+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
99
103
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
100
104
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
101
105
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
···
111
115
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
112
116
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
113
117
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
118
+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
119
+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
114
120
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
115
121
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
116
122
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
···
227
233
github.com/resend/resend-go/v2 v2.15.0 h1:B6oMEPf8IEQwn2Ovx/9yymkESLDSeNfLFaNMw+mzHhE=
228
234
github.com/resend/resend-go/v2 v2.15.0/go.mod h1:3YCb8c8+pLiqhtRFXTyFwlLvfjQtluxOr9HEh2BwCkQ=
229
235
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
230
-
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
231
-
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
236
+
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
237
+
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
232
238
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
233
239
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
234
240
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
···
268
274
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8=
269
275
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q=
270
276
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I=
277
+
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
278
+
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
271
279
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
272
280
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
273
-
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
274
-
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
275
-
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
276
-
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
277
-
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
278
-
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
281
+
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
282
+
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
283
+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 h1:QcFwRrZLc82r8wODjvyCbP7Ifp3UANaBSmhDSFjnqSc=
284
+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0/go.mod h1:CXIWhUomyWBG/oY2/r/kLp6K/cmx9e/7DLpBuuGdLCA=
285
+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
286
+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
287
+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
288
+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
289
+
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0 h1:PB3Zrjs1sG1GBX51SXyTSoOTqcDglmsk7nT6tkKPb/k=
290
+
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0/go.mod h1:U2R3XyVPzn0WX7wOIypPuptulsMcPDPs/oiSVOMVnHY=
291
+
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0 h1:T0Ec2E+3YZf5bgTNQVet8iTDW7oIk03tXHq+wkwIDnE=
292
+
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0/go.mod h1:30v2gqH+vYGJsesLWFov8u47EpYTcIQcBjKpI6pJThg=
293
+
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
294
+
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
295
+
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
296
+
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
297
+
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
298
+
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
299
+
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
300
+
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
301
+
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
302
+
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
279
303
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
280
304
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
281
305
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
282
306
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
283
307
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
284
-
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
285
-
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
308
+
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
309
+
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
286
310
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
287
311
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
288
312
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
···
357
381
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
358
382
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
359
383
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
360
-
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
361
-
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
384
+
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
385
+
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
362
386
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
363
387
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
364
388
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
···
395
419
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
396
420
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
397
421
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
398
-
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
399
-
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
422
+
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0=
423
+
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
424
+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
425
+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
426
+
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
427
+
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
428
+
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
429
+
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
400
430
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
401
431
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
402
432
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+88
telemetry/middleware.go
+88
telemetry/middleware.go
···
1
+
package telemetry
2
+
3
+
import (
4
+
"fmt"
5
+
"net/http"
6
+
"time"
7
+
8
+
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
9
+
otelmetric "go.opentelemetry.io/otel/metric"
10
+
"go.opentelemetry.io/otel/semconv/v1.13.0/httpconv"
11
+
)
12
+
13
+
func (t *Telemetry) RequestDuration() func(next http.Handler) http.Handler {
14
+
const (
15
+
metricNameRequestDurationMs = "request_duration_millis"
16
+
metricUnitRequestDurationMs = "ms"
17
+
metricDescRequestDurationMs = "Measures the latency of HTTP requests processed by the server, in milliseconds."
18
+
)
19
+
histogram, err := t.meter.Int64Histogram(
20
+
metricNameRequestDurationMs,
21
+
otelmetric.WithDescription(metricDescRequestDurationMs),
22
+
otelmetric.WithUnit(metricUnitRequestDurationMs),
23
+
)
24
+
if err != nil {
25
+
panic(fmt.Sprintf("unable to create %s histogram: %v", metricNameRequestDurationMs, err))
26
+
}
27
+
28
+
return func(next http.Handler) http.Handler {
29
+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
30
+
// capture the start time of the request
31
+
startTime := time.Now()
32
+
33
+
// execute next http handler
34
+
next.ServeHTTP(w, r)
35
+
36
+
// record the request duration
37
+
duration := time.Since(startTime)
38
+
histogram.Record(
39
+
r.Context(),
40
+
int64(duration.Milliseconds()),
41
+
otelmetric.WithAttributes(
42
+
httpconv.ServerRequest(t.serviceName, r)...,
43
+
),
44
+
)
45
+
})
46
+
}
47
+
}
48
+
49
+
func (t *Telemetry) RequestInFlight() func(next http.Handler) http.Handler {
50
+
const (
51
+
metricNameRequestInFlight = "request_in_flight"
52
+
metricDescRequestInFlight = "Measures the number of concurrent HTTP requests being processed by the server."
53
+
metricUnitRequestInFlight = "1"
54
+
)
55
+
56
+
// counter to capture requests in flight
57
+
counter, err := t.meter.Int64UpDownCounter(
58
+
metricNameRequestInFlight,
59
+
otelmetric.WithDescription(metricDescRequestInFlight),
60
+
otelmetric.WithUnit(metricUnitRequestInFlight),
61
+
)
62
+
if err != nil {
63
+
panic(fmt.Sprintf("unable to create %s counter: %v", metricNameRequestInFlight, err))
64
+
}
65
+
66
+
return func(next http.Handler) http.Handler {
67
+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
68
+
attrs := otelmetric.WithAttributes(httpconv.ServerRequest(t.serviceName, r)...)
69
+
70
+
// increase the number of requests in flight
71
+
counter.Add(r.Context(), 1, attrs)
72
+
73
+
// execute next http handler
74
+
next.ServeHTTP(w, r)
75
+
76
+
// decrease the number of requests in flight
77
+
counter.Add(r.Context(), -1, attrs)
78
+
})
79
+
}
80
+
}
81
+
82
+
func (t *Telemetry) WithRouteTag() func(next http.Handler) http.Handler {
83
+
return func(next http.Handler) http.Handler {
84
+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
85
+
otelhttp.WithRouteTag(r.URL.Path, next)
86
+
})
87
+
}
88
+
}
+65
telemetry/provider.go
+65
telemetry/provider.go
···
1
+
package telemetry
2
+
3
+
import (
4
+
"context"
5
+
"fmt"
6
+
"time"
7
+
8
+
"go.opentelemetry.io/otel"
9
+
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
10
+
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
11
+
"go.opentelemetry.io/otel/exporters/stdout/stdoutmetric"
12
+
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
13
+
"go.opentelemetry.io/otel/sdk/metric"
14
+
"go.opentelemetry.io/otel/sdk/resource"
15
+
"go.opentelemetry.io/otel/sdk/trace"
16
+
)
17
+
18
+
func NewTracerProvider(ctx context.Context, res *resource.Resource, isDev bool) (*trace.TracerProvider, error) {
19
+
var exporter trace.SpanExporter
20
+
var err error
21
+
22
+
if isDev {
23
+
exporter, err = stdouttrace.New()
24
+
if err != nil {
25
+
return nil, fmt.Errorf("failed to create stdout trace exporter: %w", err)
26
+
}
27
+
} else {
28
+
exporter, err = otlptracegrpc.New(ctx)
29
+
if err != nil {
30
+
return nil, fmt.Errorf("failed to create OTLP trace exporter: %w", err)
31
+
}
32
+
}
33
+
34
+
tp := trace.NewTracerProvider(
35
+
trace.WithBatcher(exporter),
36
+
trace.WithResource(res),
37
+
)
38
+
otel.SetTracerProvider(tp)
39
+
40
+
return tp, nil
41
+
}
42
+
43
+
func NewMeterProvider(ctx context.Context, res *resource.Resource, isDev bool) (*metric.MeterProvider, error) {
44
+
var exporter metric.Exporter
45
+
var err error
46
+
47
+
if isDev {
48
+
exporter, err = stdoutmetric.New()
49
+
if err != nil {
50
+
return nil, fmt.Errorf("failed to create stdout metric exporter: %w", err)
51
+
}
52
+
} else {
53
+
exporter, err = otlpmetricgrpc.New(ctx)
54
+
if err != nil {
55
+
return nil, fmt.Errorf("failed to create OTLP metric exporter: %w", err)
56
+
}
57
+
}
58
+
59
+
mp := metric.NewMeterProvider(
60
+
metric.WithReader(metric.NewPeriodicReader(exporter, metric.WithInterval(10*time.Second))),
61
+
metric.WithResource(res),
62
+
)
63
+
otel.SetMeterProvider(mp)
64
+
return mp, nil
65
+
}
+64
telemetry/telemetry.go
+64
telemetry/telemetry.go
···
1
+
package telemetry
2
+
3
+
import (
4
+
"context"
5
+
6
+
otelmetric "go.opentelemetry.io/otel/metric"
7
+
"go.opentelemetry.io/otel/sdk/metric"
8
+
"go.opentelemetry.io/otel/sdk/resource"
9
+
"go.opentelemetry.io/otel/sdk/trace"
10
+
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
11
+
oteltrace "go.opentelemetry.io/otel/trace"
12
+
)
13
+
14
+
type Telemetry struct {
15
+
tp *trace.TracerProvider
16
+
mp *metric.MeterProvider
17
+
18
+
meter otelmetric.Meter
19
+
tracer oteltrace.Tracer
20
+
21
+
serviceName string
22
+
serviceVersion string
23
+
}
24
+
25
+
func NewTelemetry(ctx context.Context, serviceName, serviceVersion string, isDev bool) (*Telemetry, error) {
26
+
res := resource.NewWithAttributes(
27
+
semconv.SchemaURL,
28
+
semconv.ServiceName(serviceName),
29
+
semconv.ServiceVersion(serviceVersion),
30
+
)
31
+
32
+
tp, err := NewTracerProvider(ctx, res, isDev)
33
+
if err != nil {
34
+
return nil, err
35
+
}
36
+
37
+
mp, err := NewMeterProvider(ctx, res, isDev)
38
+
if err != nil {
39
+
return nil, err
40
+
}
41
+
42
+
return &Telemetry{
43
+
tp: tp,
44
+
mp: mp,
45
+
46
+
meter: mp.Meter(serviceName),
47
+
tracer: tp.Tracer(serviceVersion),
48
+
49
+
serviceName: serviceName,
50
+
serviceVersion: serviceVersion,
51
+
}, nil
52
+
}
53
+
54
+
func (t *Telemetry) Meter() otelmetric.Meter {
55
+
return t.meter
56
+
}
57
+
58
+
func (t *Telemetry) Tracer() oteltrace.Tracer {
59
+
return t.tracer
60
+
}
61
+
62
+
func (t *Telemetry) TraceStart(ctx context.Context, name string) (context.Context, oteltrace.Span) {
63
+
return ctx, oteltrace.SpanFromContext(ctx)
64
+
}
+1
appview/config.go
+1
appview/config.go
···
17
17
CamoSharedSecret string `env:"TANGLED_CAMO_SHARED_SECRET"`
18
18
AvatarSharedSecret string `env:"TANGLED_AVATAR_SHARED_SECRET"`
19
19
AvatarHost string `env:"TANGLED_AVATAR_HOST, default=https://avatar.tangled.sh"`
20
+
EnableTelemetry bool `env:"TANGLED_TELEMETRY_ENABLED, default=false"`
20
21
}
21
22
22
23
func LoadConfig(ctx context.Context) (*Config, error) {
+7
-1
appview/state/router.go
+7
-1
appview/state/router.go
···
13
13
func (s *State) Router() http.Handler {
14
14
router := chi.NewRouter()
15
15
16
+
if s.telemetry != nil {
17
+
// top-level telemetry middleware
18
+
router.Use(s.telemetry.RequestDuration())
19
+
router.Use(s.telemetry.RequestInFlight())
20
+
router.Use(s.telemetry.WithRouteTag())
21
+
}
22
+
16
23
router.HandleFunc("/*", func(w http.ResponseWriter, r *http.Request) {
17
24
pat := chi.URLParam(r, "*")
18
25
if strings.HasPrefix(pat, "did:") || strings.HasPrefix(pat, "@") {
···
48
55
49
56
func (s *State) UserRouter() http.Handler {
50
57
r := chi.NewRouter()
51
-
52
58
// strip @ from user
53
59
r.Use(StripLeadingAt)
54
60
+29
-9
appview/state/state.go
+29
-9
appview/state/state.go
···
9
9
"log"
10
10
"log/slog"
11
11
"net/http"
12
+
"runtime/debug"
12
13
"strings"
13
14
"time"
14
15
···
24
25
"tangled.sh/tangled.sh/core/appview/pages"
25
26
"tangled.sh/tangled.sh/core/jetstream"
26
27
"tangled.sh/tangled.sh/core/rbac"
28
+
"tangled.sh/tangled.sh/core/telemetry"
27
29
)
28
30
29
31
type State struct {
30
-
db *db.DB
31
-
auth *auth.Auth
32
-
enforcer *rbac.Enforcer
33
-
tidClock *syntax.TIDClock
34
-
pages *pages.Pages
35
-
resolver *appview.Resolver
36
-
jc *jetstream.JetstreamClient
37
-
config *appview.Config
32
+
db *db.DB
33
+
auth *auth.Auth
34
+
enforcer *rbac.Enforcer
35
+
tidClock *syntax.TIDClock
36
+
pages *pages.Pages
37
+
resolver *appview.Resolver
38
+
jc *jetstream.JetstreamClient
39
+
telemetry *telemetry.Telemetry
40
+
config *appview.Config
38
41
}
39
42
40
-
func Make(config *appview.Config) (*State, error) {
43
+
func Make(ctx context.Context, config *appview.Config) (*State, error) {
41
44
d, err := db.Make(config.DbPath)
42
45
if err != nil {
43
46
return nil, err
···
59
62
60
63
resolver := appview.NewResolver()
61
64
65
+
bi, ok := debug.ReadBuildInfo()
66
+
var version string
67
+
if ok {
68
+
version = bi.Main.Version
69
+
} else {
70
+
version = "v0.0.0-unknown"
71
+
}
72
+
62
73
wrapper := db.DbWrapper{d}
63
74
jc, err := jetstream.NewJetstreamClient(
64
75
config.JetstreamEndpoint,
···
77
88
return nil, fmt.Errorf("failed to start jetstream watcher: %w", err)
78
89
}
79
90
91
+
var tele *telemetry.Telemetry
92
+
if config.EnableTelemetry {
93
+
tele, err = telemetry.NewTelemetry(ctx, "appview", version, config.Dev)
94
+
if err != nil {
95
+
return nil, fmt.Errorf("failed to setup telemetry: %w", err)
96
+
}
97
+
}
98
+
80
99
state := &State{
81
100
d,
82
101
auth,
···
85
104
pgs,
86
105
resolver,
87
106
jc,
107
+
tele,
88
108
config,
89
109
}
90
110
+4
-2
cmd/appview/main.go
+4
-2
cmd/appview/main.go
···
14
14
func main() {
15
15
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, nil)))
16
16
17
-
c, err := appview.LoadConfig(context.Background())
17
+
ctx := context.Background()
18
+
19
+
c, err := appview.LoadConfig(ctx)
18
20
if err != nil {
19
21
log.Println("failed to load config", "error", err)
20
22
return
21
23
}
22
24
23
-
state, err := state.Make(c)
25
+
state, err := state.Make(ctx, c)
24
26
25
27
if err != nil {
26
28
log.Fatal(err)