go-duck-cli 1.4.8 → 1.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -446,6 +446,14 @@ func SetupRouter(appConfig *config.Config) *gin.Engine {
446
446
  }
447
447
 
448
448
  /* System Metrics Dashboard */
449
+ @keyframes flashRedOverlay {
450
+ 0% { background: rgba(0,0,0,0.8); }
451
+ 50% { background: rgba(255,0,0,0.5); }
452
+ 100% { background: rgba(0,0,0,0.8); }
453
+ }
454
+ .alarm-flash-screen {
455
+ animation: flashRedOverlay 1s infinite !important;
456
+ }
449
457
  #sys-metrics-modal {
450
458
  display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%;
451
459
  background: rgba(0,0,0,0.8); z-index: 4000; justify-content: center; align-items: center;
@@ -468,13 +476,47 @@ func SetupRouter(appConfig *config.Config) *gin.Engine {
468
476
  .metrics-tabs { display: flex; gap: 10px; margin-bottom: 20px; }
469
477
  .metrics-tab {
470
478
  padding: 8px 16px; border: none; border-radius: 6px; cursor: pointer;
471
- font-weight: 600; background: #eee; color: #555; transition: all 0.2s;
479
+ font-weight: 600; background: #eee; color: #555;
472
480
  }
481
+ .metrics-tab:hover { background: #e0e0e0; }
473
482
  .metrics-tab.active { background: #4a90e2; color: white; }
474
-
483
+
484
+ .cpu-threads-grid {
485
+ display: grid;
486
+ grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
487
+ gap: 10px;
488
+ margin-top: 15px;
489
+ }
490
+ .cpu-chart-container {
491
+ border: 1px solid #7eb4ea;
492
+ background: #f7fbff;
493
+ display: flex;
494
+ flex-direction: column;
495
+ }
496
+ .cpu-chart-canvas {
497
+ width: 100%;
498
+ height: 50px;
499
+ display: block;
500
+ border-bottom: 1px solid #7eb4ea;
501
+ }
502
+ .cpu-chart-label {
503
+ text-align: center;
504
+ font-size: 0.65rem;
505
+ color: #333;
506
+ padding: 3px 0;
507
+ background: #eef5fb;
508
+ }
509
+
475
510
  .metrics-dashboard-grid {
476
- display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px;
477
- overflow-y: auto; padding-right: 10px;
511
+ display: grid;
512
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
513
+ gap: 20px;
514
+ overflow-y: auto;
515
+ padding-right: 10px;
516
+ }
517
+ @media (max-width: 600px) {
518
+ .metrics-tabs { flex-wrap: wrap; }
519
+ .metrics-tab { flex: 1 1 40%; text-align: center; }
478
520
  }
479
521
  .metric-card {
480
522
  background: white; border-radius: 8px; padding: 15px;
@@ -616,13 +658,20 @@ func SetupRouter(appConfig *config.Config) *gin.Engine {
616
658
  <div id="metrics-dashboard-view" class="metrics-dashboard-grid">
617
659
  <!-- CPU Card -->
618
660
  <div class="metric-card">
619
- <div class="metric-title">Process CPU</div>
661
+ <div class="metric-title" style="display:flex; justify-content: space-between;">
662
+ <span id="m-cpu-title">Process CPU</span>
663
+ <span id="m-cpu-badge" style="font-size: 0.8rem; background:#e74c3c; color:white; padding:2px 6px; border-radius:4px; display:none;">Pod Quota</span>
664
+ </div>
620
665
  <div class="metric-value"><span id="m-cpu">0.00</span><span class="metric-unit">%</span></div>
621
666
  <div class="progress-bar-container"><div id="p-cpu" class="progress-bar" style="width: 0%"></div></div>
667
+ <div id="cpu-threads-grid" class="cpu-threads-grid"></div>
622
668
  </div>
623
669
  <!-- Memory Card -->
624
670
  <div class="metric-card">
625
- <div class="metric-title">Heap Alloc</div>
671
+ <div class="metric-title" style="display:flex; justify-content: space-between;">
672
+ <span>Heap Alloc</span>
673
+ <span style="font-size: 0.8rem; color: #888; font-weight: normal;">OS: <span id="m-sys">0</span> MB</span>
674
+ </div>
626
675
  <div class="metric-value"><span id="m-heap">0</span><span class="metric-unit">MB</span></div>
627
676
  <div class="progress-bar-container"><div id="p-heap" class="progress-bar" style="width: 0%"></div></div>
628
677
  </div>
@@ -847,6 +896,25 @@ func SetupRouter(appConfig *config.Config) *gin.Engine {
847
896
  // Metrics Dashboard Logic
848
897
  const sysMetricsModal = document.getElementById('sys-metrics-modal');
849
898
  let metricsInterval = null;
899
+ let cpuThreadHistory = {};
900
+ const MAX_HISTORY_POINTS = 20;
901
+
902
+ // Audio Alarm Logic
903
+ const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
904
+ function playAlarm() {
905
+ if(audioCtx.state === 'suspended') audioCtx.resume();
906
+ const oscillator = audioCtx.createOscillator();
907
+ const gainNode = audioCtx.createGain();
908
+ oscillator.type = 'square';
909
+ oscillator.frequency.setValueAtTime(880, audioCtx.currentTime); // 880 Hz
910
+ oscillator.frequency.exponentialRampToValueAtTime(440, audioCtx.currentTime + 0.3);
911
+ gainNode.gain.setValueAtTime(0.1, audioCtx.currentTime);
912
+ gainNode.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.3);
913
+ oscillator.connect(gainNode);
914
+ gainNode.connect(audioCtx.destination);
915
+ oscillator.start();
916
+ oscillator.stop(audioCtx.currentTime + 0.3);
917
+ }
850
918
 
851
919
  function syntaxHighlight(json) {
852
920
  if (typeof json != 'string') {
@@ -896,11 +964,108 @@ func SetupRouter(appConfig *config.Config) *gin.Engine {
896
964
  .then(data => {
897
965
  // Update Dashboard UI
898
966
  const sys = data.system;
899
- document.getElementById('m-cpu').innerText = sys.process_cpu_usage.toFixed(2);
900
- updateProgressBar('p-cpu', sys.process_cpu_usage, 100);
967
+
968
+ if (sys.is_pod_cpu_limited) {
969
+ document.getElementById('m-cpu-title').innerText = "Pod CPU Quota";
970
+ document.getElementById('m-cpu-badge').style.display = 'inline-block';
971
+ document.getElementById('m-cpu').innerText = sys.pod_cpu_limit_pct.toFixed(2);
972
+ updateProgressBar('p-cpu', sys.pod_cpu_limit_pct, 100);
973
+ } else {
974
+ document.getElementById('m-cpu-title').innerText = "Process CPU";
975
+ document.getElementById('m-cpu-badge').style.display = 'none';
976
+ document.getElementById('m-cpu').innerText = sys.process_cpu_usage.toFixed(2);
977
+ updateProgressBar('p-cpu', sys.process_cpu_usage, 100);
978
+ }
979
+
980
+ const threadsGrid = document.getElementById('cpu-threads-grid');
981
+ if (threadsGrid && sys.cpu_threads_usage) {
982
+ if (threadsGrid.children.length !== sys.cpu_threads_usage.length) {
983
+ let html = '';
984
+ sys.cpu_threads_usage.forEach((val, idx) => {
985
+ html += `<div class="cpu-chart-container" title="Core ${idx}">
986
+ <canvas id="t-cpu-canvas-${idx}" class="cpu-chart-canvas"></canvas>
987
+ <div id="t-cpu-label-${idx}" class="cpu-chart-label">T${idx}: 0%</div>
988
+ </div>`;
989
+ });
990
+ threadsGrid.innerHTML = html;
991
+
992
+ // Set internal canvas resolution to match computed CSS size for crisp rendering
993
+ sys.cpu_threads_usage.forEach((val, idx) => {
994
+ const canvas = document.getElementById(`t-cpu-canvas-${idx}`);
995
+ if (canvas) {
996
+ canvas.width = canvas.offsetWidth;
997
+ canvas.height = canvas.offsetHeight;
998
+ cpuThreadHistory[idx] = new Array(MAX_HISTORY_POINTS).fill(0);
999
+ }
1000
+ });
1001
+ }
1002
+
1003
+ sys.cpu_threads_usage.forEach((val, idx) => {
1004
+ // Update History Array
1005
+ if (!cpuThreadHistory[idx]) {
1006
+ cpuThreadHistory[idx] = new Array(MAX_HISTORY_POINTS).fill(0);
1007
+ }
1008
+ cpuThreadHistory[idx].push(val);
1009
+ if (cpuThreadHistory[idx].length > MAX_HISTORY_POINTS) {
1010
+ cpuThreadHistory[idx].shift();
1011
+ }
1012
+
1013
+ // Render Text Label
1014
+ const label = document.getElementById(`t-cpu-label-${idx}`);
1015
+ if (label) {
1016
+ label.innerText = `T${idx}: ${val.toFixed(0)}%`;
1017
+ }
1018
+
1019
+ // Render Canvas Sparkline
1020
+ const canvas = document.getElementById(`t-cpu-canvas-${idx}`);
1021
+ if (canvas) {
1022
+ const ctx = canvas.getContext('2d');
1023
+ const width = canvas.width;
1024
+ const height = canvas.height;
1025
+ const history = cpuThreadHistory[idx];
1026
+
1027
+ ctx.clearRect(0, 0, width, height);
1028
+
1029
+ // Draw light grid lines like Task Manager
1030
+ ctx.strokeStyle = '#cce3f9';
1031
+ ctx.lineWidth = 1;
1032
+ ctx.beginPath();
1033
+ for(let i=1; i<4; i++) {
1034
+ ctx.moveTo(0, height * (i/4));
1035
+ ctx.lineTo(width, height * (i/4));
1036
+ }
1037
+ for(let i=1; i<5; i++) {
1038
+ ctx.moveTo(width * (i/5), 0);
1039
+ ctx.lineTo(width * (i/5), height);
1040
+ }
1041
+ ctx.stroke();
1042
+
1043
+ // Draw Data Line
1044
+ ctx.beginPath();
1045
+ ctx.strokeStyle = '#1a73e8';
1046
+ ctx.lineWidth = 1.5;
1047
+
1048
+ const step = width / (MAX_HISTORY_POINTS - 1);
1049
+ history.forEach((point, pIdx) => {
1050
+ const x = pIdx * step;
1051
+ const y = height - (point / 100) * height;
1052
+ if (pIdx === 0) ctx.moveTo(x, y);
1053
+ else ctx.lineTo(x, y);
1054
+ });
1055
+ ctx.stroke();
1056
+
1057
+ // Draw Fill Underneath
1058
+ ctx.lineTo(width, height);
1059
+ ctx.lineTo(0, height);
1060
+ ctx.fillStyle = 'rgba(26, 115, 232, 0.2)';
1061
+ ctx.fill();
1062
+ }
1063
+ });
1064
+ }
901
1065
 
902
1066
  document.getElementById('m-heap').innerText = sys.heap_alloc_mb;
903
- updateProgressBar('p-heap', sys.heap_alloc_mb, sys.heap_sys_mb > 0 ? sys.heap_sys_mb : 1024);
1067
+ document.getElementById('m-sys').innerText = sys.total_mem_mb;
1068
+ updateProgressBar('p-heap', sys.heap_alloc_mb, sys.total_mem_mb > 0 ? sys.total_mem_mb : 1024);
904
1069
 
905
1070
  document.getElementById('m-goroutines').innerText = sys.goroutines;
906
1071
  document.getElementById('m-uptime').innerText = sys.uptime;
@@ -910,6 +1075,24 @@ func SetupRouter(appConfig *config.Config) *gin.Engine {
910
1075
  document.getElementById('m-http-ok').innerText = data.status_codes['200'] ? data.status_codes['200'].count : 0;
911
1076
  document.getElementById('m-http-fail').innerText = data.failed_calls;
912
1077
 
1078
+ // Alarm Detection (Ceiling > 90%)
1079
+ let isAlarmState = false;
1080
+ let currentCpuVal = sys.is_pod_cpu_limited ? sys.pod_cpu_limit_pct : sys.process_cpu_usage;
1081
+ if (currentCpuVal > 90) isAlarmState = true;
1082
+ if (sys.total_mem_mb > 0 && (sys.heap_alloc_mb / sys.total_mem_mb) > 0.90) isAlarmState = true;
1083
+
1084
+ const modalWrapper = document.getElementById('sys-metrics-modal');
1085
+ const modalContent = document.querySelector('.metrics-content');
1086
+
1087
+ if (isAlarmState) {
1088
+ playAlarm();
1089
+ if(modalWrapper) modalWrapper.classList.add('alarm-flash-screen');
1090
+ if(modalContent) modalContent.style.boxShadow = '0 0 50px rgba(255, 0, 0, 0.6)';
1091
+ } else {
1092
+ if(modalWrapper) modalWrapper.classList.remove('alarm-flash-screen');
1093
+ if(modalContent) modalContent.style.boxShadow = '0 10px 40px rgba(0,0,0,0.2)';
1094
+ }
1095
+
913
1096
  // Endpoints Table
914
1097
  const tbody = document.getElementById('m-endpoints-body');
915
1098
  tbody.innerHTML = '';
@@ -0,0 +1,23 @@
1
+
2
+ receivers:
3
+ otlp:
4
+ protocols:
5
+ grpc:
6
+ http:
7
+ processors:
8
+ batch:
9
+ resourcedetection:
10
+ detectors: [env, system]
11
+ exporters:
12
+ logging:
13
+ loglevel: debug
14
+ otlp:
15
+ endpoint: "jaeger:4317"
16
+ tls:
17
+ insecure: true
18
+ service:
19
+ pipelines:
20
+ traces:
21
+ receivers: [otlp]
22
+ processors: [batch, resourcedetection]
23
+ exporters: [logging, otlp]
package/test-go/go.mod ADDED
@@ -0,0 +1,64 @@
1
+ module testapp
2
+
3
+ go 1.26.1
4
+
5
+ require (
6
+ github.com/gin-gonic/gin v1.12.0
7
+ github.com/shirou/gopsutil/v3 v3.24.5
8
+ go.opentelemetry.io/otel v1.44.0
9
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0
10
+ go.opentelemetry.io/otel/sdk v1.44.0
11
+ google.golang.org/grpc v1.81.1
12
+ )
13
+
14
+ require (
15
+ github.com/bytedance/gopkg v0.1.3 // indirect
16
+ github.com/bytedance/sonic v1.15.0 // indirect
17
+ github.com/bytedance/sonic/loader v0.5.0 // indirect
18
+ github.com/cenkalti/backoff/v5 v5.0.3 // indirect
19
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
20
+ github.com/cloudwego/base64x v0.1.6 // indirect
21
+ github.com/gabriel-vasile/mimetype v1.4.12 // indirect
22
+ github.com/gin-contrib/sse v1.1.0 // indirect
23
+ github.com/go-logr/logr v1.4.3 // indirect
24
+ github.com/go-logr/stdr v1.2.2 // indirect
25
+ github.com/go-ole/go-ole v1.3.0 // indirect
26
+ github.com/go-playground/locales v0.14.1 // indirect
27
+ github.com/go-playground/universal-translator v0.18.1 // indirect
28
+ github.com/go-playground/validator/v10 v10.30.1 // indirect
29
+ github.com/goccy/go-json v0.10.5 // indirect
30
+ github.com/goccy/go-yaml v1.19.2 // indirect
31
+ github.com/google/uuid v1.6.0 // indirect
32
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
33
+ github.com/json-iterator/go v1.1.12 // indirect
34
+ github.com/klauspost/cpuid/v2 v2.3.0 // indirect
35
+ github.com/leodido/go-urn v1.4.0 // indirect
36
+ github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e // indirect
37
+ github.com/mattn/go-isatty v0.0.20 // indirect
38
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
39
+ github.com/modern-go/reflect2 v1.0.2 // indirect
40
+ github.com/pelletier/go-toml/v2 v2.2.4 // indirect
41
+ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
42
+ github.com/quic-go/qpack v0.6.0 // indirect
43
+ github.com/quic-go/quic-go v0.59.0 // indirect
44
+ github.com/shoenig/go-m1cpu v0.2.1 // indirect
45
+ github.com/tklauser/go-sysconf v0.4.0 // indirect
46
+ github.com/tklauser/numcpus v0.12.0 // indirect
47
+ github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
48
+ github.com/ugorji/go/codec v1.3.1 // indirect
49
+ github.com/yusufpapurcu/wmi v1.2.4 // indirect
50
+ go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
51
+ go.opentelemetry.io/auto/sdk v1.2.1 // indirect
52
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect
53
+ go.opentelemetry.io/otel/metric v1.44.0 // indirect
54
+ go.opentelemetry.io/otel/trace v1.44.0 // indirect
55
+ go.opentelemetry.io/proto/otlp v1.10.0 // indirect
56
+ golang.org/x/arch v0.22.0 // indirect
57
+ golang.org/x/crypto v0.51.0 // indirect
58
+ golang.org/x/net v0.55.0 // indirect
59
+ golang.org/x/sys v0.45.0 // indirect
60
+ golang.org/x/text v0.37.0 // indirect
61
+ google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect
62
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
63
+ google.golang.org/protobuf v1.36.11 // indirect
64
+ )
package/test-go/go.sum ADDED
@@ -0,0 +1,154 @@
1
+ github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
2
+ github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
3
+ github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE=
4
+ github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k=
5
+ github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE=
6
+ github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
7
+ github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
8
+ github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
9
+ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
10
+ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
11
+ github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
12
+ github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
13
+ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
14
+ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
15
+ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
16
+ github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
17
+ github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
18
+ github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
19
+ github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
20
+ github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
21
+ github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc=
22
+ github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
23
+ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
24
+ github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
25
+ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
26
+ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
27
+ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
28
+ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
29
+ github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
30
+ github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
31
+ github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
32
+ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
33
+ github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
34
+ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
35
+ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
36
+ github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w=
37
+ github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM=
38
+ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
39
+ github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
40
+ github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
41
+ github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
42
+ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
43
+ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
44
+ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
45
+ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
46
+ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
47
+ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
48
+ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
49
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
50
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
51
+ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
52
+ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
53
+ github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
54
+ github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
55
+ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
56
+ github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
57
+ github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e h1:Q6MvJtQK/iRcRtzAscm/zF23XxJlbECiGPyRicsX+Ak=
58
+ github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
59
+ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
60
+ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
61
+ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
62
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
63
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
64
+ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
65
+ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
66
+ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
67
+ github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
68
+ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
69
+ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
70
+ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
71
+ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
72
+ github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
73
+ github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
74
+ github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
75
+ github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
76
+ github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
77
+ github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
78
+ github.com/shoenig/go-m1cpu v0.2.1 h1:yqRB4fvOge2+FyRXFkXqsyMoqPazv14Yyy+iyccT2E4=
79
+ github.com/shoenig/go-m1cpu v0.2.1/go.mod h1:KkDOw6m3ZJQAPHbrzkZki4hnx+pDRR1Lo+ldA56wD5w=
80
+ github.com/shoenig/test v1.7.0 h1:eWcHtTXa6QLnBvm0jgEabMRN/uJ4DMV3M8xUGgRkZmk=
81
+ github.com/shoenig/test v1.7.0/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI=
82
+ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
83
+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
84
+ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
85
+ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
86
+ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
87
+ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
88
+ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
89
+ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
90
+ github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
91
+ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
92
+ github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
93
+ github.com/tklauser/go-sysconf v0.4.0 h1:7H0uAN+7RkwWRaxhYXDLqa5V3LPrJeV8wmD9dRUgPQU=
94
+ github.com/tklauser/go-sysconf v0.4.0/go.mod h1:8mTNWyog7H+MpKijp4VmKJAd2bbYQ2zuUwkYRbUArPI=
95
+ github.com/tklauser/numcpus v0.12.0 h1:NR85qdvHA9pFse3x3weVZ0r0ST8R6l5RHbZrlRaqob4=
96
+ github.com/tklauser/numcpus v0.12.0/go.mod h1:ABHeXzJnr/qqwguhClkZKT1/8VABcYrsyUiUGobwWJg=
97
+ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
98
+ github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
99
+ github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
100
+ github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
101
+ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
102
+ github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
103
+ go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
104
+ go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
105
+ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
106
+ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
107
+ go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
108
+ go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
109
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI=
110
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80=
111
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0 h1:qazEJlUOQzhCpzQpFETGby7EdqjI1wsd0W+6Gg1SCTU=
112
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0/go.mod h1:fOD2Yefuxixkx3ahVNf0O/PERb6r4OlbxfATVnYvzCo=
113
+ go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
114
+ go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
115
+ go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
116
+ go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
117
+ go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
118
+ go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
119
+ go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
120
+ go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
121
+ go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
122
+ go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
123
+ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
124
+ go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
125
+ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
126
+ go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
127
+ golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
128
+ golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
129
+ golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
130
+ golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
131
+ golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
132
+ golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
133
+ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
134
+ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
135
+ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
136
+ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
137
+ golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
138
+ golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
139
+ golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
140
+ golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
141
+ gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
142
+ gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
143
+ google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8=
144
+ google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY=
145
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
146
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
147
+ google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
148
+ google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
149
+ google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
150
+ google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
151
+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
152
+ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
153
+ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
154
+ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -0,0 +1,88 @@
1
+
2
+ package telemetry
3
+
4
+ import (
5
+ "sync"
6
+ "time"
7
+ "github.com/gin-gonic/gin"
8
+ "undefined/config"
9
+ )
10
+
11
+ type EndpointStats struct {
12
+ Count int64 `json:"count"`
13
+ MeanTime float64 `json:"mean_time_ms"`
14
+ MaxTime float64 `json:"max_time_ms"`
15
+ TotalTime float64 `json:"-"`
16
+ }
17
+
18
+ type StatusStats struct {
19
+ Count int64 `json:"count"`
20
+ MeanTime float64 `json:"mean_time_ms"`
21
+ MaxTime float64 `json:"max_time_ms"`
22
+ TotalTime float64 `json:"-"`
23
+ }
24
+
25
+ type AppMetrics struct {
26
+ Mu sync.RWMutex
27
+ StartTime time.Time
28
+ Endpoints map[string]*EndpointStats
29
+ StatusCodes map[int]*StatusStats
30
+ FailedCalls int64
31
+ }
32
+
33
+ var globalMetrics = &AppMetrics{
34
+ StartTime: time.Now(),
35
+ Endpoints: make(map[string]*EndpointStats),
36
+ StatusCodes: make(map[int]*StatusStats),
37
+ }
38
+
39
+ func MetricsTrackingMiddleware(cfg *config.Config) gin.HandlerFunc {
40
+ return func(c *gin.Context) {
41
+ start := time.Now()
42
+ c.Next()
43
+ duration := float64(time.Since(start).Milliseconds())
44
+
45
+ status := c.Writer.Status()
46
+ method := c.Request.Method
47
+ path := c.FullPath()
48
+ if path == "" {
49
+ path = "unknown"
50
+ }
51
+ endpointKey := method + " " + path
52
+
53
+ globalMetrics.Mu.Lock()
54
+ defer globalMetrics.Mu.Unlock()
55
+
56
+ // Status Code tracking
57
+ if _, exists := globalMetrics.StatusCodes[status]; !exists {
58
+ globalMetrics.StatusCodes[status] = &StatusStats{}
59
+ }
60
+ sStat := globalMetrics.StatusCodes[status]
61
+ sStat.Count++
62
+ sStat.TotalTime += duration
63
+ sStat.MeanTime = sStat.TotalTime / float64(sStat.Count)
64
+ if duration > sStat.MaxTime {
65
+ sStat.MaxTime = duration
66
+ }
67
+
68
+ if status >= 400 {
69
+ globalMetrics.FailedCalls++
70
+ }
71
+
72
+ // Endpoint tracking
73
+ if _, exists := globalMetrics.Endpoints[endpointKey]; !exists {
74
+ globalMetrics.Endpoints[endpointKey] = &EndpointStats{}
75
+ }
76
+ eStat := globalMetrics.Endpoints[endpointKey]
77
+ eStat.Count++
78
+ eStat.TotalTime += duration
79
+ eStat.MeanTime = eStat.TotalTime / float64(eStat.Count)
80
+ if duration > eStat.MaxTime {
81
+ eStat.MaxTime = duration
82
+ }
83
+ }
84
+ }
85
+
86
+ func GetGlobalMetrics() *AppMetrics {
87
+ return globalMetrics
88
+ }
@@ -0,0 +1,69 @@
1
+
2
+ package telemetry
3
+
4
+ import (
5
+ "context"
6
+ "fmt"
7
+ "log"
8
+
9
+ "undefined/config"
10
+ "go.opentelemetry.io/otel"
11
+ "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
12
+ "go.opentelemetry.io/otel/propagation"
13
+ "go.opentelemetry.io/otel/sdk/resource"
14
+ sdktrace "go.opentelemetry.io/otel/sdk/trace"
15
+ semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
16
+ "google.golang.org/grpc"
17
+ "google.golang.org/grpc/credentials/insecure"
18
+ )
19
+
20
+ // InitTelemetry initializes OpenTelemetry SDK
21
+ func InitTelemetry(cfg *config.Config) (func(context.Context) error, error) {
22
+ if !cfg.GoDuck.Telemetry.OTel.Enabled {
23
+ log.Println("OpenTelemetry is disabled.")
24
+ return func(context.Context) error { return nil }, nil
25
+ }
26
+
27
+ ctx := context.Background()
28
+
29
+ // 1. Setup Resource
30
+ res, err := resource.New(ctx,
31
+ resource.WithAttributes(
32
+ semconv.ServiceNameKey.String(cfg.GoDuck.Name),
33
+ semconv.ServiceVersionKey.String(cfg.GoDuck.Version),
34
+ ),
35
+ )
36
+ if err != nil {
37
+ return nil, fmt.Errorf("failed to create resource: %w", err)
38
+ }
39
+
40
+ // 2. Setup OTLP Exporter (gRPC)
41
+ conn, err := grpc.DialContext(ctx, cfg.GoDuck.Telemetry.OTel.Endpoint,
42
+ grpc.WithTransportCredentials(insecure.NewCredentials()),
43
+ grpc.WithBlock(),
44
+ )
45
+ if err != nil {
46
+ return nil, fmt.Errorf("failed to create gRPC connection to OTel collector: %w", err)
47
+ }
48
+
49
+ traceExporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithGRPCConn(conn))
50
+ if err != nil {
51
+ return nil, fmt.Errorf("failed to create trace exporter: %w", err)
52
+ }
53
+
54
+ // 3. Setup Tracer Provider
55
+ bsp := sdktrace.NewBatchSpanProcessor(traceExporter)
56
+ tp := sdktrace.NewTracerProvider(
57
+ sdktrace.WithSampler(sdktrace.TraceIDRatioBased(cfg.GoDuck.Telemetry.OTel.SamplerRatio)),
58
+ sdktrace.WithResource(res),
59
+ sdktrace.WithSpanProcessor(bsp),
60
+ )
61
+ otel.SetTracerProvider(tp)
62
+
63
+ // 4. Setup Text Map Propagator
64
+ otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
65
+
66
+ log.Printf("OpenTelemetry initialized with endpoint: %s", cfg.GoDuck.Telemetry.OTel.Endpoint)
67
+
68
+ return tp.Shutdown, nil
69
+ }