Webhook 사용자 정의 Body 템플릿¶
템플릿 문법을 사용하여 Webhook 알림 Body 내용을 사용자 정의할 수 있습니다:
- 동적 렌더링:
{{ 필드명 }}을 사용하여 알림 필드를 직접 삽입합니다 (예:{{ host }},{{ df_status }}); - 데이터 처리:
{{ 변수 | 함수() }}를 사용하여 데이터 형식을 변환합니다 (예: 타임스탬프를 날짜로, 숫자를 백분율로); - 조건 분기:
{% if ... %}를 사용하여 상태에 따라 Body를 다르게 출력합니다; - JSON 출력:
to_json_dumps를 통해 JSON 객체, 배열, 숫자, 불리언 등을 출력합니다; - 실시간 쿼리:
DQL("쿼리문")을 임베드하여 관련 데이터를 가져옵니다 (예: 호스트 IP, 시스템 정보).
기본 템플릿 변수¶
템플릿 변수의 기본 문법은 {{ 필드명 }}이며, 이벤트 관련 동적 정보를 렌더링하는 데 사용됩니다. 다음은 Webhook 사용자 정의 Body에서 자주 사용되는 템플릿 변수와 그 용도입니다:
| 템플릿 변수 | 타입 | 설명 |
|---|---|---|
date, timestamp |
Integer | 이벤트 발생 시간, Unix 타임스탬프 (초 단위) |
df_status |
String(Enum) | 이벤트 상태, 가능한 값: 긴급 critical, 중요 error, 경고 warning, 정상 ok, 데이터 단절 nodata |
df_event_id |
String | 이벤트 고유 ID |
df_event_link |
String | 이벤트 상세 페이지 링크 주소 |
df_title |
String | 이벤트 제목 |
df_message |
String | 이벤트 내용 |
df_dimension_tags |
String | 이벤트 차원, 감지 대상을 식별하는 데 사용 (예: {"host":"web-001"}) |
df_dimension_tags_obj |
Dict | 이벤트 차원 객체, 객체 방식으로 차원 필드를 읽기 용이 |
df_monitor_id |
String | 알림 정책 ID |
df_monitor_name |
String | 알림 정책 이름 |
df_monitor_checker_id |
String | 모니터 ID |
df_monitor_checker_name |
String | 모니터 이름 |
df_monitor_checker_value |
String | 감지값, 모니터가 감지한 값 |
Result |
Integer, Float, String, Dict, List | 감지된 원시값, df_monitor_checker_value와 동일하게 감지 시 생성된 값이지만 원래 타입 유지 |
Result_with_unit |
String | 단위가 포함된 감지값 |
df_related_data |
Dict | 관련 데이터 |
df_fault_id |
String | 현재 장애 ID, 최초 장애 이벤트의 df_event_id 값 |
df_fault_status |
String(Enum) | 현재 장애 상태, 가능한 값: 정상 ok, 장애 fault |
df_fault_start_time |
Integer | 현재 장애 발생 시간, Unix 타임스탬프 (초 단위) |
df_fault_duration |
Integer | 현재 장애 지속 시간 (초 단위) |
df_site_name |
String | 현재 Guance 노드 이름 |
df_workspace_name |
String | 소속 워크스페이스 이름 |
df_workspace_uuid |
String | 소속 워크스페이스 ID |
df_label |
List | 모니터 태그 목록 |
df_alert_policy_names |
List | 적중된 알림 정책 이름 목록 |
df_sent_target_types |
List | 본 이벤트가 전송된 알림 대상 유형 목록 |
df_event |
Dict | 전체 이벤트 데이터 |
df_dimension_tags의 각 필드 |
String | df_dimension_tags의 각 필드는 최상위 레벨로 추출됨 (예: host, region) |
참고:
df_monitor_checker_value는 호환성을 보장하기 위해 String 타입으로 강제 변환됩니다;- 감지값의 원래 타입을 유지해야 하는 경우
Result를 사용하는 것이 좋습니다; - 모니터 유형, 이벤트 소스 및 알림 시나리오에 따라 사용 가능한 변수가 다를 수 있습니다.
템플릿 변수 예시¶
모니터 by에 region과 host가 구성되어 있다고 가정하고, Webhook 사용자 정의 Body 템플릿은 다음과 같습니다:
{
"title": "모니터 {{ df_monitor_checker_name }}이(가) {{ df_dimension_tags }}에서 장애를 발견했습니다",
"region": "{{ region }}",
"host": "{{ host }}",
"status": "{{ df_status }}",
"value": "{{ Result }}",
"monitor": "{{ df_monitor_checker_name }}",
"policy": "{{ df_monitor_name }}"
}
error 이벤트가 발생한 후 렌더링된 Body 출력은 다음과 같습니다:
{
"title": "모니터 모니터001이(가) {\"region\":\"hangzhou\",\"host\":\"web-001\"}에서 장애를 발견했습니다",
"region": "hangzhou",
"host": "web-001",
"status": "error",
"value": "90.12345",
"monitor": "모니터001",
"policy": "팀001"
}
JSON Body 출력¶
Webhook 사용자 정의 Body는 일반적으로 최종적으로 유효한 JSON을 출력해야 합니다. 먼저 JSON 객체를 정의한 다음 to_json_dumps 함수를 사용하여 문자열 이스케이프, 객체/배열 중첩, 쉼표 누락과 같은 JSON 문법 오류를 방지하는 것이 좋습니다.
예시:
{% set json_data = {
"event_id": df_event_id,
"title": df_title,
"status": df_status,
"status_text": df_status | to_status_human,
"event_link": df_event_link,
"monitor": {
"id": df_monitor_id,
"name": df_monitor_name,
"checker_id": df_monitor_checker_id,
"checker_name": df_monitor_checker_name
},
"dimension": {
"raw": df_dimension_tags,
"object": df_dimension_tags_obj,
"pretty": df_dimension_tags | to_pretty_tags
},
"value": {
"raw": Result,
"with_unit": Result_with_unit,
"type": Result | type_name
}
} %}
{{ json_data | to_json_dumps }}
출력 결과는 다음과 같습니다:
{
"event_id": "event-xxxxx",
"title": "CPU 사용률 과다",
"status": "error",
"status_text": "중요",
"event_link": "https://console.guance.com/keyevents/monitor/events/event-xxxxx",
"monitor": {
"id": "altpl_xxxxx",
"name": "팀001",
"checker_id": "rul_xxxxx",
"checker_name": "모니터001"
},
"dimension": {
"raw": "{\"region\":\"hangzhou\",\"host\":\"web-001\"}",
"object": {
"region": "hangzhou",
"host": "web-001"
},
"pretty": "region:hangzhou, host:web-001"
},
"value": {
"raw": 90.12345,
"with_unit": "90.12345%",
"type": "float"
}
}
필드별 JSON 렌더링¶
각 필드를 개별적으로 렌더링할 수도 있습니다. 이때 필드 타입에 주의해야 합니다:
{
"event_id": "{{ df_event_id }}",
"status": "{{ df_status }}",
"status_text": "{{ df_status | to_status_human }}",
"checker_name": "{{ df_monitor_checker_name }}",
"dimension": {{ df_dimension_tags_obj | to_json_dumps }},
"value": {{ Result | to_json_dumps }},
"related_data": {{ df_related_data | to_json_dumps }}
}
설명:
- 문자열 필드는 큰따옴표 안에 넣을 수 있습니다 (예:
"{{ df_status }}"); - 객체, 배열, 숫자, 불리언은
to_json_dumps를 사용하는 것이 좋습니다; - 객체나 배열을
"{{ df_related_data }}"와 같이 작성하면 수신 측에서 JSON 객체가 아닌 문자열을 얻게 되므로 권장하지 않습니다.
특수 시나리오 변수¶
RUM 메트릭 감지¶
RUM 메트릭 감지에서는 위의 일반 템플릿 변수 외에 다음 템플릿 변수를 추가로 지원합니다:
| 템플릿 변수 | 타입 | 설명 |
|---|---|---|
app_id |
String | 애플리케이션 ID |
app_name |
String | 애플리케이션 이름 |
app_type |
String | 애플리케이션 유형 |
특수 문자 필드 처리¶
감지 구성에서 차원 필드에 특수 문자(예: -, @)가 포함된 경우 (예: host-name, @level), 일반 변수 이름으로 직접 사용할 수 없어 템플릿 렌더링이 실패합니다.
잘못된 작성법:
해결 방법은 다음 형식을 사용하여 참조하는 것입니다:
{{ df_event["host-name"] }}
{{ df_event["@level"] }}
{{ df_dimension_tags_obj["host-name"] }}
{{ df_dimension_tags_obj["@level"] }}
템플릿 함수¶
이벤트의 필드 값을 직접 표시하는 것 외에도 템플릿 함수를 사용하여 필드 값을 추가로 처리하고 출력을 최적화할 수 있습니다.
기본 문법은 다음과 같습니다:
구체적인 예시는 다음과 같습니다:
템플릿 함수를 사용하기 전에 템플릿 변수에 대한 연산이 필요한 경우 괄호를 추가하는 것을 잊지 마세요:
사용 가능한 템플릿 함수 목록은 다음과 같습니다:
| 템플릿 함수 | 매개변수 | 설명 |
|---|---|---|
to_datetime |
tz="Asia/Shanghai" |
Unix 초 단위 타임스탬프 또는 ISO8601 날짜 문자열을 날짜-시간 문자열로 변환 |
to_date_range_human |
lang="zh" |
초 단위 기간을 읽기 쉬운 형식으로 변환 (예: 1일 2시간 3분 1초) |
to_status_human |
lang="zh" |
df_status를 읽기 쉬운 상태로 변환 |
to_fixed |
ndigits=0 |
숫자를 지정된 소수 자릿수로 고정 출력 |
to_round |
ndigits=0 |
숫자를 지정된 소수 자릿수로 반올림 |
to_percent |
ndigits=0 |
소수를 백분율 형식으로 변환 |
to_pretty_tags |
separators=(':', ', ') |
dict 또는 JSON 문자열 형식의 태그를 읽기 쉬운 태그 텍스트로 변환 |
limit_lines |
lines=3, chars=None |
출력 줄 수 제한, 동시에 줄당 문자 수 제한 가능 |
limit_chars / limit_text |
chars=50 |
출력 문자 수 제한, limit_text는 limit_chars의 별칭 |
type_name |
없음 | 데이터 타입 이름 출력 |
to_int |
없음 | 정수로 변환 |
to_float |
없음 | 부동 소수점 숫자로 변환 |
to_str |
없음 | 문자열로 변환 |
to_json_dumps |
indent=None |
dict, list 등을 JSON 직렬화 문자열로 변환 |
is_error |
없음 | 객체가 오류인지 확인, 내장 DQL이 정상 실행되었는지 판단하는 데 자주 사용 |
length |
없음 | 문자열, 리스트, 딕셔너리 등 객체의 길이를 가져옴 |
replace |
old, new, count=-1 |
문자열 내용 교체, count=-1은 전체 교체를 의미 |
abs |
없음 | 숫자의 절대값을 가져옴 |
템플릿 함수 예시¶
{% set body = {
"object": df_dimension_tags | to_pretty_tags,
"time": date | to_datetime,
"status": df_status | to_status_human,
"value": Result | to_fixed(2),
"percent": Result | to_percent(1),
"duration": df_fault_duration | to_date_range_human,
"message": df_message | limit_lines(3, 80)
} %}
{{ body | to_json_dumps }}
템플릿 분기¶
조건 분기를 통해 상태에 따른 차별화된 Body 출력을 구현할 수 있습니다.
기본 문법은 다음과 같습니다:
템플릿 분기 예시¶
{% set level = "info" %}
{% if df_status == "critical" %}
{% set level = "critical" %}
{% elif df_status == "error" %}
{% set level = "error" %}
{% elif df_status == "warning" %}
{% set level = "warning" %}
{% elif df_status == "nodata" %}
{% set level = "nodata" %}
{% endif %}
{% set body = {
"level": level,
"status": df_status,
"status_text": df_status | to_status_human,
"title": df_title,
"event_link": df_event_link
} %}
{{ body | to_json_dumps }}
내장 DQL 쿼리 함수¶
템플릿 변수만으로 렌더링 요구 사항을 충족할 수 없는 경우 내장 DQL 쿼리 함수를 사용하여 데이터를 추가로 조회할 수 있습니다. 내장 DQL은 현재 워크스페이스, 현재 감지 시간 범위 내에서 DQL을 실행하며, 일반적으로 쿼리 결과의 첫 번째 데이터를 템플릿 변수로 사용합니다.
호출 형식은 다음과 같습니다:
내장 DQL 쿼리 예시¶
{% set host_info = DQL("O::HOST:(host_ip, os) { region = ?, host = ? }", region, host) %}
{% set body = {
"host": host,
"region": region,
"host_ip": host_info.host_ip,
"os": host_info.os,
"status": df_status,
"event_link": df_event_link
} %}
{{ body | to_json_dumps }}
내장 DQL 쿼리 함수 세부 사항¶
- 내장 DQL 쿼리는 템플릿의 시작 부분에 배치해야 합니다;
- DQL 문의 매개변수 자리 표시자
?는 특정 값으로 대체될 때 자동으로 이스케이프됩니다; - DQL에 템플릿 변수를 전달할 때 매개변수 부분은 변수명을 직접 작성합니다 (예:
host);{{ host }}로 작성하지 마십시오; - 쿼리 결과 변수명은 기존 템플릿 변수, 템플릿 함수와 중복되지 않아야 합니다;
- DQL에서 함수를 사용하여 필드를 처리하는 경우 템플릿에서 읽기 쉽도록
AS로 필드 별칭을 지정하는 것이 좋습니다; - DQL 쿼리 결과 필드명에 특수 문자가 포함된 경우
{{ host_info["host-name"] }}형식으로 읽어야 합니다; is_error와 함께 사용하여 DQL이 정상 실행되었는지 확인할 수 있습니다.
전체 Body 예시¶
다음 예시는 알림 이벤트를 외부 이벤트 센터로 전송하는 데 적합합니다:
{% set is_recovery = df_status == "ok" %}
{% set priority = "P0" if df_status == "critical" else ("P1" if df_status in ["error", "nodata"] else ("P2" if df_status == "warning" else "INFO")) %}
{% set body = {
"source": "guance",
"event_id": df_event_id,
"event_link": df_event_link,
"title": df_title,
"status": df_status,
"status_text": df_status | to_status_human,
"priority": priority,
"is_recovery": is_recovery,
"monitor": {
"policy_id": df_monitor_id,
"policy_name": df_monitor_name,
"checker_id": df_monitor_checker_id,
"checker_name": df_monitor_checker_name
},
"object": {
"tags": df_dimension_tags_obj,
"text": df_dimension_tags | to_pretty_tags
},
"value": {
"raw": Result,
"with_unit": Result_with_unit,
"fixed_2": Result | to_fixed(2)
},
"fault": {
"fault_id": df_fault_id,
"fault_status": df_fault_status,
"start_time": df_fault_start_time | to_datetime,
"duration_seconds": df_fault_duration,
"duration_text": df_fault_duration | to_date_range_human
},
"notify": {
"alert_policy_names": df_alert_policy_names,
"sent_target_types": df_sent_target_types
}
} %}
{{ body | to_json_dumps }}
주의사항¶
- Webhook 사용자 정의 Body의 최종 렌더링 결과는 반드시 유효한 JSON이어야 합니다;
- 필드 값에 큰따옴표, 줄바꿈, 특수 문자가 포함될 수 있는 경우
to_json_dumps를 사용하여 출력하는 것이 좋습니다; - 객체, 배열, 숫자, 불리언을 강제로 문자열로 감싸지 마십시오;
- 템플릿을 디버깅할 때는 먼저 소수의 필드로 렌더링 결과를 확인한 다음 점차 복잡한 필드와 조건 분기를 추가하는 것이 좋습니다;
- Webhook 사용자 정의 Body 템플릿은 요청 Body 렌더링만 담당합니다. 요청 주소, 헤더 등의 구성은 Webhook 알림 대상에서 유지 관리됩니다.