과거 메트릭 수집(Historical Metrics Ingestion)
과거 메트릭 수집(HMI, Historical Metrics Ingestion)을 활성화하면 제출 시점보다 1시간 이상 오래된 타임스탬프를 가진 커스텀 메트릭 값도 수집할 수 있어요. 장애 복구, 잘못된 값의 수정, IoT 지연 관리 같은 다양한 사용 사례에서 유용하답니다. 이 문서에서는 과거 메트릭 수집의 개념, 구성 방법, 제출 방법, 지연 시간과 과금 방식을 함께 살펴봐요.
출처: 문서
본문
개요
과거 메트릭 수집을 활성화하면 커스텀 메트릭 값을 제출 시점보다 1시간 이상 오래된 타임스탬프로 수집할 수 있어요. 단, 전체 메트릭 보존 기간(기본 15개월)보다 오래된 값은 수집할 수 없어요.
메트릭에 과거 메트릭 수집을 활성화하면 장애로부터의 복구, 잘못된 값의 수정, IoT 지연 관리 등 다양한 사용 사례에서 도움이 돼요.
과거 메트릭 수집이란?
{% image source="https://docs.dd-static.net/images/metrics/custom_metrics/historical_metrics/diagram_historical-metrics-ingestion_1_240202.eb1e69f20ee389ff32cfb8f6df8cd047.png?auto=format&fit=max&w=850 1x, https://docs.dd-static.net/images/metrics/custom_metrics/historical_metrics/diagram_historical-metrics-ingestion_1_240202.eb1e69f20ee389ff32cfb8f6df8cd047.png?auto=format&fit=max&w=850&dpr=2 2x" alt="Diagram showing the ingestion flow for Historical Metrics enabled" /%}
Datadog은 제출 시점을 기준으로 1시간보다 오래된 타임스탬프를 가진 메트릭 포인트를 *과거 메트릭(historical metrics)*으로 분류해요. 과거 메트릭 수집이 활성화되어 있지 않으면, 제출 시점보다 1시간 이상 오래된 메트릭 값은 수집되지 않아요.
예를 들어 메트릭(exampleMetricA)이 오후 1시(EST)에 Datadog으로 값을 보내는데, 그 값의 타임스탬프가 오전 10시(EST)라면, 이 메트릭 값은 제출 시점보다 3시간 오래된 타임스탬프를 가지므로 과거로 분류돼요.
과거 메트릭 수집이 활성화된 상태에서 같은 타임스탬프와 같은 태그 값 조합으로 여러 값을 Datadog에 제출하면, Datadog은 가장 최근에 제출된 값을 유지해요. 즉, 같은 타임스탬프 안에서 메트릭을 값 X로 제출하고 값 Y로도 보냈다면, 더 최근에 제출된 값이 유지되는 거예요.
Metrics Summary 페이지에서 counts, rates, gauges 메트릭 타입에 대해 과거 메트릭 수집을 활성화하여 과거 메트릭 값 수집을 시작할 수 있어요.
참고: 과거 메트릭 수집은 distribution 메트릭이나 로그 같은 다른 Datadog 데이터 타입에서 생성된 커스텀 메트릭에는 사용할 수 없어요.
구성
특정 메트릭에 대해 과거 메트릭 수집을 활성화하려면:
- Metrics Summary 페이지로 이동하세요.
- 과거 메트릭 수집을 활성화할 메트릭 이름을 클릭해 메트릭 상세 사이드 패널을 엽니다.
- 사이드 패널의 Advanced 섹션에서 Configure를 클릭하세요.
- Enable historical metrics 토글을 선택하고 Save를 누르세요.
{% image source="https://docs.dd-static.net/images/metrics/custom_metrics/historical_metrics/enable_historical_metrics.2b38888238064f80845ac6b5a911ad0d.png?auto=format&fit=max&w=850 1x, https://docs.dd-static.net/images/metrics/custom_metrics/historical_metrics/enable_historical_metrics.2b38888238064f80845ac6b5a911ad0d.png?auto=format&fit=max&w=850&dpr=2 2x" alt="Metrics Summary page showing the Historical Metrics facets panel and the Advanced section of an open Metric detail panel with the Enable historical metrics option selected" /%}
여러 메트릭에 대한 일괄 구성
각 메트릭을 개별적으로 구성하는 대신, 여러 메트릭에 대해 한 번에 과거 메트릭 수집을 활성화하거나 비활성화할 수 있어요.
- Metrics Summary 페이지로 이동해 Configure Metrics 드롭다운을 클릭하세요.
- Enable historical metrics를 선택하세요.
- 해당 네임스페이스와 일치하는 모든 메트릭을 선택할 메트릭 네임스페이스 접두사를 지정하세요.
- (선택 사항) 네임스페이스의 모든 메트릭에 대해 과거 메트릭 수집을 비활성화하려면 Historical metrics 토글을 클릭하세요.
{% image source="https://docs.dd-static.net/images/metrics/custom_metrics/historical_metrics/historical_metrics_ingestion_toggle.95ab83f2a82095eeafa6cb38c194a27f.png?auto=format&fit=max&w=850 1x, https://docs.dd-static.net/images/metrics/custom_metrics/historical_metrics/historical_metrics_ingestion_toggle.95ab83f2a82095eeafa6cb38c194a27f.png?auto=format&fit=max&w=850&dpr=2 2x" alt="Historical metrics ingestion toggle" /%}
과거 메트릭 제출
과거 메트릭 수집을 활성화한 후에는 API 또는 Agent를 통해 과거 타임스탬프를 가진 메트릭 값을 제출할 수 있어요.
API
API를 사용하면 페이로드에 과거 타임스탬프를 가진 메트릭 값을 제출할 수 있어요(단, 위에서 설명한 사용자 인터페이스를 통해 해당 메트릭 이름이 이미 과거 메트릭을 받아들이도록 활성화되어 있어야 해요).
{% tab title="Python" %}
"""
Submit metrics returns "Payload accepted" response
"""
from datetime import datetime
from datadog_api_client import ApiClient, Configuration
from datadog_api_client.v2.api.metrics_api import MetricsApi
from datadog_api_client.v2.model.metric_intake_type import MetricIntakeType
from datadog_api_client.v2.model.metric_payload import MetricPayload
from datadog_api_client.v2.model.metric_point import MetricPoint
from datadog_api_client.v2.model.metric_resource import MetricResource
from datadog_api_client.v2.model.metric_series import MetricSeries
body = MetricPayload(
series=[
MetricSeries(
metric="system.load.1",
type=MetricIntakeType.UNSPECIFIED,
points=[
MetricPoint(
""" Add historical timestamp here """
timestamp=int(datetime.now().timestamp()),
""" *********************** """
value=0.7,
),
],
resources=[
MetricResource(
name="dummyhost",
type="host",
),
],
),
],
)
configuration = Configuration()
with ApiClient(configuration) as api_client:
api_instance = MetricsApi(api_client)
response = api_instance.submit_metrics(body=body)
print(response)
{% /tab %}
{% tab title="Java" %}
// Submit metrics returns "Payload accepted" response
import com.datadog.api.client.ApiClient;
import com.datadog.api.client.ApiException;
import com.datadog.api.client.v2.api.MetricsApi;
import com.datadog.api.client.v2.model.IntakePayloadAccepted;
import com.datadog.api.client.v2.model.MetricIntakeType;
import com.datadog.api.client.v2.model.MetricPayload;
import com.datadog.api.client.v2.model.MetricPoint;
import com.datadog.api.client.v2.model.MetricResource;
import com.datadog.api.client.v2.model.MetricSeries;
import java.time.OffsetDateTime;
import java.util.Collections;
public class Example {
public static void main(String[] args) {
ApiClient defaultClient = ApiClient.getDefaultApiClient();
MetricsApi apiInstance = new MetricsApi(defaultClient);
MetricPayload body =
new MetricPayload()
.series(
Collections.singletonList(
new MetricSeries()
.metric("system.load.1")
.type(MetricIntakeType.UNSPECIFIED)
.points(
Collections.singletonList(
new MetricPoint()
//Add historical timestamp here
.timestamp(OffsetDateTime.now().toInstant().getEpochSecond())
//***********************
.value(0.7)))
.resources(
Collections.singletonList(
new MetricResource().name("dummyhost").type("host")))));
try {
IntakePayloadAccepted result = apiInstance.submitMetrics(body);
System.out.println(result);
} catch (ApiException e) {
System.err.println("Exception when calling MetricsApi#submitMetrics");
System.err.println("Status code: " + e.getCode());
System.err.println("Reason: " + e.getResponseBody());
System.err.println("Response headers: " + e.getResponseHeaders());
e.printStackTrace();
}
}
}
{% /tab %}
{% tab title="Go" %}
// Submit metrics returns "Payload accepted" response
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"time"
"github.com/DataDog/datadog-api-client-go/v2/api/datadog"
"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
)
func main() {
body := datadogV2.MetricPayload{
Series: []datadogV2.MetricSeries{
{
Metric: "system.load.1",
Type: datadogV2.METRICINTAKETYPE_UNSPECIFIED.Ptr(),
Points: []datadogV2.MetricPoint{
{
//Add historical timestamp here
Timestamp: datadog.PtrInt64(time.Now().Unix()),
//***********************
Value: datadog.PtrFloat64(0.7),
},
},
Resources: []datadogV2.MetricResource{
{
Name: datadog.PtrString("dummyhost"),
Type: datadog.PtrString("host"),
},
},
},
},
}
ctx := datadog.NewDefaultContext(context.Background())
configuration := datadog.NewConfiguration()
apiClient := datadog.NewAPIClient(configuration)
api := datadogV2.NewMetricsApi(apiClient)
resp, r, err := api.SubmitMetrics(ctx, body, *datadogV2.NewSubmitMetricsOptionalParameters())
if err != nil {
fmt.Fprintf(os.Stderr, "Error when calling `MetricsApi.SubmitMetrics`: %v\n", err)
fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
}
responseContent, _ := json.MarshalIndent(resp, "", " ")
fmt.Fprintf(os.Stdout, "Response from `MetricsApi.SubmitMetrics`:\n%s\n", responseContent)
}
{% /tab %}
{% tab title="Ruby" %}
# Submit metrics returns "Payload accepted" response
require "datadog_api_client"
api_instance = DatadogAPIClient::V2::MetricsAPI.new
body = DatadogAPIClient::V2::MetricPayload.new({
series: [
DatadogAPIClient::V2::MetricSeries.new({
metric: "system.load.1",
type: DatadogAPIClient::V2::MetricIntakeType::UNSPECIFIED,
points: [
DatadogAPIClient::V2::MetricPoint.new({
#Add historical timestamp here
timestamp: Time.now.to_i,
#***********************
value: 0.7,
}),
],
resources: [
DatadogAPIClient::V2::MetricResource.new({
name: "dummyhost",
type: "host",
}),
],
}),
],
})
p api_instance.submit_metrics(body)
{% /tab %}
{% tab title="Typescript" %}
/**
* Submit metrics returns "Payload accepted" response
*/
import { client, v2 } from "@datadog/datadog-api-client";
const configuration = client.createConfiguration();
const apiInstance = new v2.MetricsApi(configuration);
const params: v2.MetricsApiSubmitMetricsRequest = {
body: {
series: [
{
metric: "system.load.1",
type: 0,
points: [
{
//Add historical timestamp here
timestamp: Math.round(new Date().getTime() / 1000),
//***********************
value: 0.7,
},
],
resources: [
{
name: "dummyhost",
type: "host",
},
],
},
],
},
};
apiInstance
.submitMetrics(params)
.then((data: v2.IntakePayloadAccepted) => {
console.log(
"API called successfully. Returned data: " + JSON.stringify(data)
);
})
.catch((error: any) => console.error(error));
{% /tab %}
{% tab title="Curl" %}
## Dynamic Points
# Post time-series data that can be graphed on Datadog's dashboards.
# Template variables
export NOW="$(date +%s)"
# Curl command
curl -X POST "https://api.datadoghq.com/api/v2/series" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "DD-API-KEY: *** \
-d @- << EOF
{
"series": [
{
"metric": "system.load.1",
"type": 0,
"points": [
{
# Add historical timestamp here
"timestamp": 1636629071,
# ***********************
"value": 0.7
}
],
"resources": [
{
"name": "dummyhost",
"type": "host"
}
]
}
]
}
EOF
{% /tab %}
Agent
Agent로 과거 메트릭을 제출하려면 Agent 버전 7.40.0 이상이 설치되어 있어야 해요. 이 버전에는 Java, GoLang, .NET을 지원하는 업데이트된 DogStatsD 인터페이스가 포함되어 있어요. 이를 통해 Agent를 통해 지연된 메트릭 포인트를 보낼 수 있어요.
{% tab title="Java" %}
import com.timgroup.statsd.NonBlockingStatsDClientBuilder;
import com.timgroup.statsd.StatsDClient;
import java.util.Random;
public class DogStatsdClient {
public static void main(String[] args) throws Exception {
StatsDClient Statsd = new NonBlockingStatsDClientBuilder()
.prefix("statsd").
.hostname("localhost")
.port(8125)
.build();
Statsd.gaugeWithTimestamp("example_metric.gauge_with_timestamp", new Random().nextInt(20), 1205794800, new String[]{"environment:dev"});
Statsd.countWithTimestamp("example_metric.count_with_timestamp", new Random().nextInt(20), 1205794800, new String[]{"environment:dev"});
}
}
{% /tab %}
{% tab title="Go" %}
package main
import (
"log"
"time"
"github.com/DataDog/datadog-go/statsd"
)
func main() {
statsd, err := statsd.New("127.0.0.1:8125")
if err != nil {
log.Fatal(err)
}
ts := time.Date(2008, time.March, 17, 23, 0, 0, 0, time.UTC)
statsd.GaugeWithTimestamp("example_metric.gauge_with_timestamp", 12, []string{"environment:dev"}, 1, ts)
statsd.CountWithTimestamp("example_metric.count_with_timestamp", 12, []string{"environment:dev"}, 1, ts)
}
{% /tab %}
{% tab title=".NET" %}
using StatsdClient;
public class DogStatsdClient
{
public static void Main()
{
var dogstatsdConfig = new StatsdConfig
{
StatsdServerName = "127.0.0.1",
StatsdPort = 8125,
};
using (var dogStatsdService = new DogStatsdService())
{
dogStatsdService.Configure(dogstatsdConfig);
var random = new Random(0);
var dto = new DateTimeOffset(2008, 03, 17, 23, 00, 00, new TimeSpan(0, 0, 0))
dogStatsdService.Gauge("example_metric.gauge_with_timestamp", 10, tags: new[] {"environment:dev"}, dto);
dogStatsdService.Counter("example_metric.count_with_timestamp", 10, tags: new[] {"environment:dev"}, dto);
}
}
}
{% /tab %}
과거 메트릭 수집의 지연 시간
과거 메트릭 수집은 메트릭 타임스탬프가 얼마나 과거인지에 따라 다양한 지연 시간을 가져요.
| 메트릭 지연 정도 | 수집 지연 시간 |
|---|---|
| 1~12시간 | 거의 실시간 수집(최대 1시간) |
| 12시간~30일 | 최대 14시간 지연 |
| 30일 초과 | 14시간 초과 지연 |
과거 메트릭 수집 과금
과거 메트릭은 인덱싱된 커스텀 메트릭으로 계산되고 과금돼요. 과금 가능한 커스텀 메트릭은 제출된 메트릭의 타임스탬프를 기준으로 결정되며, 타임스탬프가 오늘이든 15개월 전이든 상관없어요. 해당 메트릭 이름과 태그 값 조합이 (타임스탬프와 무관하게) 어떤 값이라도 활발하게 보고하고 있다면, 제출된 시간대에서 활성 상태로 간주돼요.
다음 예시를 가정해 볼게요.
- 3,000개의 고유 태그 값 조합
- 1,500개의 실시간 메트릭
- 1,500개의 과거 메트릭
- 한 달 720시간(30일)
- 커스텀 메트릭 비용 100개당 $5
$(1500/ 720) ⋅ (5 / 100) + $(1500/ 720) ⋅ (5 / 100) = $0.21
인덱싱된 과거 메트릭은 Plan and Usage 페이지의 Usage Summary 섹션에서 추적할 수 있어요.
{% image source="https://docs.dd-static.net/images/metrics/custom_metrics/historical_metrics/custom_metrics_usage_summary.1082255f73efa51ebe0102f098071a79.png?auto=format&fit=max&w=850 1x, https://docs.dd-static.net/images/metrics/custom_metrics/historical_metrics/custom_metrics_usage_summary.1082255f73efa51ebe0102f098071a79.png?auto=format&fit=max&w=850&dpr=2 2x" alt="Usage Summary section of the Plan and Usage page, which shows both custom indexed and historical indexed metrics" /%}
자세한 내용은 Custom Metrics billing 문서를 참고해 주세요.
메트릭 이름(Metric Name) 가격 책정 하의 과금
조직이 카디널리티 가격 책정 대신 Metric Name 가격 책정을 사용한다면 HMI 과금은 달라져요. HMI 사용량은 메트릭의 원래 타임스탬프가 아니라 수집 시간을 기준으로 계산돼요. 각 HMI datapoint는 수집된 볼륨과 인덱싱된 볼륨 양쪽에 기여해요.
Metric Name 가격 책정 모델에 대한 자세한 내용은 Metric Name Pricing for Custom Metrics를 참고해 주세요.
더 알아보기 (Learn more)
추가로 도움이 되는 문서, 링크, 글: