diff --git a/apps/backend/apps/admin/src/metric.ts b/apps/backend/apps/admin/src/metric.ts index 1b7c974bb2..026370d492 100644 --- a/apps/backend/apps/admin/src/metric.ts +++ b/apps/backend/apps/admin/src/metric.ts @@ -6,38 +6,73 @@ import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics' import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions' +import * as http from 'http' -const startMetricsExporter = () => { - const options = { - url: - 'http://' + process.env.OTEL_EXPORTER_OTLP_ENDPOINT_URL + '/v1/metrics', // Grafana Agent Metric을 받는 url - headers: {}, - concurrencyLimit: 5 - } - const exporter = new OTLPMetricExporter(options) +const getInstanceId = (): Promise => { + return new Promise((resolve, reject) => { + const options = { + hostname: '169.254.169.254', + path: '/latest/meta-data/instance-id', + method: 'GET', + timeout: 1000 + } - const resource = new Resource({ - [SemanticResourceAttributes.SERVICE_NAME]: 'backend-admin-metric', - [SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0', - environment: 'production' // 사용자 정의 속성 - }) + const req = http.request(options, (res) => { + let data = '' + res.on('data', (chunk: Buffer) => { + data += chunk.toString() + }) + res.on('end', () => { + resolve(data) + }) + }) - // Creates MeterProvider and installs the exporter as a MetricReader - const meterProvider = new MeterProvider({ - resource: resource - }) - meterProvider.addMetricReader( - new PeriodicExportingMetricReader({ - exporter, - exportIntervalMillis: 1000 + req.on('error', (error: Error) => { + console.error(error) + reject(error) }) - ) - const hostMetrics = new HostMetrics({ - meterProvider, - name: 'backend-admin-host-metric' + req.end() }) - hostMetrics.start() +} + +const startMetricsExporter = async () => { + try { + const instanceId = await getInstanceId() + const options = { + url: + 'http://' + process.env.OTEL_EXPORTER_OTLP_ENDPOINT_URL + '/v1/metrics', // Grafana Agent Metric을 받는 url + headers: {}, + concurrencyLimit: 5 + } + const exporter = new OTLPMetricExporter(options) + + const resource = new Resource({ + [SemanticResourceAttributes.SERVICE_NAME]: 'backend-admin-metric', + [SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0', + [SemanticResourceAttributes.SERVICE_INSTANCE_ID]: instanceId, + environment: 'production' // 사용자 정의 속성 + }) + + // Creates MeterProvider and installs the exporter as a MetricReader + const meterProvider = new MeterProvider({ + resource + }) + meterProvider.addMetricReader( + new PeriodicExportingMetricReader({ + exporter, + exportIntervalMillis: 1000 + }) + ) + + const hostMetrics = new HostMetrics({ + meterProvider, + name: 'backend-admin-host-metric' + }) + hostMetrics.start() + } catch (e) { + console.error('Failed to initialize the metric', e) + } } export default startMetricsExporter diff --git a/apps/backend/apps/client/src/metric.ts b/apps/backend/apps/client/src/metric.ts index 4546335e52..240dc02b20 100644 --- a/apps/backend/apps/client/src/metric.ts +++ b/apps/backend/apps/client/src/metric.ts @@ -6,38 +6,73 @@ import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics' import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions' +import * as http from 'http' -const startMetricsExporter = () => { - const options = { - url: - 'http://' + process.env.OTEL_EXPORTER_OTLP_ENDPOINT_URL + '/v1/metrics', // Grafana Agent Metric을 받는 url - headers: {}, - concurrencyLimit: 5 - } - const exporter = new OTLPMetricExporter(options) +const getInstanceId = (): Promise => { + return new Promise((resolve, reject) => { + const options = { + hostname: '169.254.169.254', + path: '/latest/meta-data/instance-id', + method: 'GET', + timeout: 1000 + } - const resource = new Resource({ - [SemanticResourceAttributes.SERVICE_NAME]: 'backend-client-metric', - [SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0', - environment: 'production' // 사용자 정의 속성 - }) + const req = http.request(options, (res) => { + let data = '' + res.on('data', (chunk: Buffer) => { + data += chunk.toString() + }) + res.on('end', () => { + resolve(data) + }) + }) - // Creates MeterProvider and installs the exporter as a MetricReader - const meterProvider = new MeterProvider({ - resource: resource - }) - meterProvider.addMetricReader( - new PeriodicExportingMetricReader({ - exporter, - exportIntervalMillis: 1000 + req.on('error', (error: Error) => { + console.error(error) + reject(error) }) - ) - const hostMetrics = new HostMetrics({ - meterProvider, - name: 'backend-client-host-metric' + req.end() }) - hostMetrics.start() +} + +const startMetricsExporter = async () => { + try { + const instanceId = await getInstanceId() + const options = { + url: + 'http://' + process.env.OTEL_EXPORTER_OTLP_ENDPOINT_URL + '/v1/metrics', // Grafana Agent Metric을 받는 url + headers: {}, + concurrencyLimit: 5 + } + const exporter = new OTLPMetricExporter(options) + + const resource = new Resource({ + [SemanticResourceAttributes.SERVICE_NAME]: 'backend-client-metric', + [SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0', + [SemanticResourceAttributes.SERVICE_INSTANCE_ID]: instanceId, + environment: 'production' // 사용자 정의 속성 + }) + + // Creates MeterProvider and installs the exporter as a MetricReader + const meterProvider = new MeterProvider({ + resource + }) + meterProvider.addMetricReader( + new PeriodicExportingMetricReader({ + exporter, + exportIntervalMillis: 1000 + }) + ) + + const hostMetrics = new HostMetrics({ + meterProvider, + name: 'backend-client-host-metric' + }) + hostMetrics.start() + } catch (e) { + console.error('Failed to initialize the metric', e) + } } export default startMetricsExporter diff --git a/apps/iris/go.mod b/apps/iris/go.mod index 36e0ba2b67..eb049881ab 100644 --- a/apps/iris/go.mod +++ b/apps/iris/go.mod @@ -3,8 +3,8 @@ module github.com/skkuding/codedang/apps/iris go 1.21 require ( - github.com/aws/aws-sdk-go-v2 v1.26.0 - github.com/aws/aws-sdk-go-v2/credentials v1.17.9 + github.com/aws/aws-sdk-go-v2 v1.26.1 + github.com/aws/aws-sdk-go-v2/credentials v1.17.10 github.com/aws/aws-sdk-go-v2/service/s3 v1.53.0 github.com/rabbitmq/amqp091-go v1.9.0 github.com/redis/go-redis/v9 v9.5.1 @@ -23,14 +23,20 @@ require ( require ( github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 // indirect + github.com/aws/aws-sdk-go-v2/config v1.27.10 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.6 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.4 // indirect - github.com/aws/smithy-go v1.20.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.20.4 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 // indirect + github.com/aws/smithy-go v1.20.2 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect diff --git a/apps/iris/go.sum b/apps/iris/go.sum index f6b4dbf04f..26d36296c5 100644 --- a/apps/iris/go.sum +++ b/apps/iris/go.sum @@ -2,26 +2,42 @@ github.com/aws/aws-sdk-go-v2 v1.25.3 h1:xYiLpZTQs1mzvz5PaI6uR0Wh57ippuEthxS4iK5v github.com/aws/aws-sdk-go-v2 v1.25.3/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I= github.com/aws/aws-sdk-go-v2 v1.26.0 h1:/Ce4OCiM3EkpW7Y+xUnfAFpchU78K7/Ug01sZni9PgA= github.com/aws/aws-sdk-go-v2 v1.26.0/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I= +github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA= +github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 h1:gTK2uhtAPtFcdRRJilZPx8uJLL2J85xK11nKtWL0wfU= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1/go.mod h1:sxpLb+nZk7tIfCWChfd+h4QwHNUR57d8hA1cleTkjJo= +github.com/aws/aws-sdk-go-v2/config v1.27.10 h1:PS+65jThT0T/snC5WjyfHHyUgG+eBoupSDV+f838cro= +github.com/aws/aws-sdk-go-v2/config v1.27.10/go.mod h1:BePM7Vo4OBpHreKRUMuDXX+/+JWP38FLkzl5m27/Jjs= github.com/aws/aws-sdk-go-v2/credentials v1.17.7 h1:WJd+ubWKoBeRh7A5iNMnxEOs982SyVKOJD+K8HIezu4= github.com/aws/aws-sdk-go-v2/credentials v1.17.7/go.mod h1:UQi7LMR0Vhvs+44w5ec8Q+VS+cd10cjwgHwiVkE0YGU= github.com/aws/aws-sdk-go-v2/credentials v1.17.9 h1:N8s0/7yW+h8qR8WaRlPQeJ6czVMNQVNtNdUqf6cItao= github.com/aws/aws-sdk-go-v2/credentials v1.17.9/go.mod h1:446YhIdmSV0Jf/SLafGZalQo+xr2iw7/fzXGDPTU1yQ= +github.com/aws/aws-sdk-go-v2/credentials v1.17.10 h1:qDZ3EA2lv1KangvQB6y258OssCHD0xvaGiEDkG4X/10= +github.com/aws/aws-sdk-go-v2/credentials v1.17.10/go.mod h1:6t3sucOaYDwDssHQa0ojH1RpmVmF5/jArkye1b2FKMI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3 h1:ifbIbHZyGl1alsAhPIYsHOg5MuApgqOvVeI8wIugXfs= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3/go.mod h1:oQZXg3c6SNeY6OZrDY+xHcF4VGIEoNotX2B4PrDeoJI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 h1:0ScVK/4qZ8CIW0k8jOeFVsyS/sAiXpYxRBLolMkuLQM= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4/go.mod h1:84KyjNZdHC6QZW08nfHI6yZgPd+qRgaWcYsyLUo3QY8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5/go.mod h1:FSaRudD0dXiMPK2UjknVwwTYyZMRsHv3TtkabsZih5I= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3 h1:Qvodo9gHG9F3E8SfYOspPeBt0bjSbsevK8WhRAUHcoY= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3/go.mod h1:vCKrdLXtybdf/uQd/YfVR2r5pcbNuEYKzMQpcxmeSJw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 h1:sHmMWWX5E7guWEFQ9SVo6A3S4xpPrWnd77a6y4WM6PU= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4/go.mod h1:WjpDrhWisWOIoS9n3nk67A3Ll1vfULJ9Kq6h29HTD48= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 h1:PG1F3OD1szkuQPzDw3CIQsRIrtTlUC3lP84taWzHlq0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5/go.mod h1:jU1li6RFryMz+so64PpKtudI+QzbKoIEivqdf6LNpOc= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.3 h1:mDnFOE2sVkyphMWtTH+stv0eW3k0OTx94K63xpxHty4= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.3/go.mod h1:V8MuRVcCRt5h1S+Fwu8KbC7l/gBGo3yBAyUbJM2IJOk= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.4 h1:SIkD6T4zGQ+1YIit22wi37CGNkrE7mXV1vNA5VpI3TI= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.4/go.mod h1:XfeqbsG0HNedNs0GT+ju4Bs+pFAwsrlzcRdMvdNVf5s= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.5 h1:mbWNpfRUTT6bnacmvOTKXZjR/HycibdWzNpfbrbLDIs= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.5/go.mod h1:FCOPWGjsshkkICJIn9hq9xr6dLKtyaWpuUojiN3W1/8= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.6 h1:NkHCgg0Ck86c5PTOzBZ0JRccI51suJDg5lgFtxBu1ek= @@ -30,6 +46,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5 h1:K/NXvIftO github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5/go.mod h1:cl9HGLV66EnCmMNzq4sYOti+/xo8w34CsgzVtm2GgsY= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 h1:b+E7zIUHMmcB4Dckjpkapoy47W6C9QBv/zoUP+Hn8Kc= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6/go.mod h1:S2fNV0rxrP78NhPbCZeQgY8H9jdDMeGtwcfZIRxzBqU= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 h1:ogRAwT1/gxJBcSWDMZlgyFUM962F51A5CRhDLbxLdmo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7/go.mod h1:YCsIZhXfRPLFFCl5xxY+1T9RKzOKjCut+28JSX2DnAk= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.3 h1:4t+QEX7BsXz98W8W1lNvMAG+NX8qHz2CjLBxQKku40g= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.3/go.mod h1:oFcjjUq5Hm09N9rpxTdeMeLeQcxS7mIkBkL8qUKng+A= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.4 h1:uDj2K47EM1reAYU9jVlQ1M5YENI1u6a/TxJpf6AeOLA= @@ -40,8 +58,16 @@ github.com/aws/aws-sdk-go-v2/service/s3 v1.52.1 h1:Y/TTvxMdYwNvhzolvneV1wEEN/ncQ github.com/aws/aws-sdk-go-v2/service/s3 v1.52.1/go.mod h1:MGTaf3x/+z7ZGugCGvepnx2DS6+caCYYqKhzVoLNYPk= github.com/aws/aws-sdk-go-v2/service/s3 v1.53.0 h1:r3o2YsgW9zRcIP3Q0WCmttFVhTuugeKIvT5z9xDspc0= github.com/aws/aws-sdk-go-v2/service/s3 v1.53.0/go.mod h1:w2E4f8PUfNtyjfL6Iu+mWI96FGttE03z3UdNcUEC4tA= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.4 h1:WzFol5Cd+yDxPAdnzTA5LmpHYSWinhmSj4rQChV0ee8= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.4/go.mod h1:qGzynb/msuZIE8I75DVRCUXw3o3ZyBmUvMwQ2t/BrGM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 h1:Jux+gDDyi1Lruk+KHF91tK2KCuY61kzoCpvtvJJBtOE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4/go.mod h1:mUYPBhaF2lGiukDEjJX2BLRRKTmoUSitGDUgM4tRxak= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 h1:cwIxeBttqPN3qkaAjcEcsh8NYr8n2HZPkcKgPAi1phU= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.6/go.mod h1:FZf1/nKNEkHdGGJP/cI2MoIMquumuRK6ol3QQJNDxmw= github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw= github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= +github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= diff --git a/apps/iris/src/observability/metric.go b/apps/iris/src/observability/metric.go index 4be2c48944..50ca2db58c 100644 --- a/apps/iris/src/observability/metric.go +++ b/apps/iris/src/observability/metric.go @@ -2,6 +2,7 @@ package observability import ( "context" + "io" "os" "runtime" "time" @@ -13,6 +14,9 @@ import ( sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.24.0" + + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" ) const defaultMetricDuration time.Duration = 3 * time.Second @@ -45,6 +49,7 @@ func newMetricResource() (*resource.Resource, error) { resource.NewWithAttributes(semconv.SchemaURL, semconv.ServiceName("iris-metric"), semconv.ServiceVersion("0.1.0"), + semconv.ServiceInstanceID(getInstanceId()), )) } @@ -105,3 +110,30 @@ func GetCPUMeter(meter metric.Meter, duration time.Duration) { reportErr(err, "failed to create CPU meter") } } + +func getInstanceId() string { + cfg, err := config.LoadDefaultConfig(context.TODO()) + if err != nil { + reportErr(err, "failed to get Config Of AWS") + return "Instance-Id-Not-Found" + } + + client := imds.NewFromConfig(cfg) + output, err := client.GetMetadata(context.TODO(), &imds.GetMetadataInput{ + Path: "instance-id", + }) + + if err != nil { + reportErr(err, "failed to get Instance Id") + return "Instance-Id-Not-Found" + } + + defer output.Content.Close() + + bytes, err := io.ReadAll(output.Content) + if err != nil { + reportErr(err, "failed to Type Cast from Metadata Output to String") + return "Instance-Id-Not-Found" + } + return string(bytes) +}