Dynamic Instrumentation 표현식 언어 (Expression Language)
Dynamic Instrumentation 표현식 언어는 메트릭 계측 표현식, 스팬 태그 값, 계측 조건을 구성하는 데 도움을 주는 언어예요. 일반적인 프로그래밍 언어의 문법을 차용하지만, 고유한 규칙도 갖고 있어요. 이 언어로 지역 변수, 메서드 매개변수, 객체 내 중첩 필드에 접근할 수 있고, 비교·논리 연산자도 사용할 수 있어요.
출처: 문서
본문
지원되지 않는 사이트 안내: 이 제품은 다음 Datadog 사이트(app.ddog-gov.com, us2.ddog-gov.com)에서는 지원되지 않아요. 선택한 Datadog 사이트와는 호환되지 않아요.
개요 (Overview)
Dynamic Instrumentation 표현식 언어는 메트릭 계측 표현식, 스팬 태그 값, 계측 조건을 구성하는 데 도움을 줘요. 일반적인 프로그래밍 언어의 문법 요소를 차용하지만 고유한 규칙도 있어요. 이 언어는 지역 변수, 메서드 매개변수, 객체 내 중첩 필드에 접근할 수 있고 비교·논리 연산자 사용을 지원해요.
예시:
someVar.someFieldrequest.headers["Host"]any(post.tags, {@it == "debugger"})@duration > 10 && len(p.data) < 100
일반적으로 표현식 언어는 다음을 지원해요:
- 객체 내 지역 변수, 메서드 매개변수, 깊게 중첩된 필드와 속성에 접근.
- 조건에서 변수·필드·상수를 비교하는 비교 연산자(
<,>,>=,<=,==,!=,instanceof) 사용. 예:localVar1.field1.field2 != 15. - 복잡한 Boolean 조건을 만드는 논리 연산자(
&&,||,!또는not(...)) 사용. 예:!isEmpty(user.email) && not(contains(user.name, "abc")). null리터럴 사용(Python에서는 자동으로None, Ruby에서는nil로 변환돼요).
다음은 지원하지 않아요:
- 메서드 호출. Dynamic Instrumentation은 부작용(side effect)이 발생할 수 있는 코드 실행을 허용하지 않아요. 다만
private필드에는 직접 접근할 수 있어요. - 이 페이지에서 설명한 것 외의 다른 네이티브 프로그래밍 언어 문법.
표현식 언어를 더 편리하게 쓰려면 자동 완성과 검색(Preview)을 사용해 보세요.
응용 (Applications)
표현식은 메트릭을 생성하고, 필터링된 데이터를 내보내는 조건으로 사용될 수 있어요.
예를 들어 len(data)를 메트릭 표현식으로 사용해 문자열 길이의 히스토그램을 만들 수 있어요. 메트릭 표현식은 숫자로 평가되어야 해요.
스팬 태그 값에서 표현식은 템플릿의 정적 부분과 대괄호로 구분돼요. 예: User name is {user.name}. 태그 값 표현식은 어떤 값으로든 평가될 수 있어요.
계측 조건은 Boolean으로 평가되어야 해요. 예:
startsWith(user.name, "abc")len(str) > 20a == b
컨텍스트 변수 (Contextual variables)
표현식 언어는 계측 시나리오별로 컨텍스트 변수를 제공해요. 메서드 계측 변수(@return, @duration, @exception)는 메서드 전체를 계측할 때만 사용할 수 있고, 컬렉션·사전 변수(@it, @key, @value)는 컬렉션을 필터링·변환하는 predicate 표현식 안에서만 사용할 수 있어요.
| 키워드 | 설명 |
|---|---|
@return |
메서드 반환 값에 접근할 수 있게 해 줘요. |
@duration |
메서드 호출 실행 시간에 접근할 수 있게 해 줘요. 밀리초 단위의 부동소수점 값이에요. |
@exception |
메서드 내에서 발생한 예외에 접근할 수 있게 해 줘요(처리되지 않은 예외가 있을 때만 사용 가능). |
@it |
컬렉션 반복 중 현재 요소에 접근할 수 있게 해 줘요. 리스트 연산의 predicate에서 사용돼요. |
@key |
사전 반복 중 현재 키에 접근할 수 있게 해 줘요. 사전 연산의 predicate에서 사용돼요. |
@value |
사전 반복 중 현재 값에 접근할 수 있게 해 줘요. 사전 연산의 predicate에서 사용돼요. |
일반 연산 (General operations)
다음 예시는 Hello, world! 값을 가진 myString이라는 변수가 있다고 가정해요:
| 연산 | 설명 | 예시 |
|---|---|---|
isDefined(var) |
변수가 정의되어 있는지 확인해요. 현재 스코프에 변수가 있으면 true, 없으면 false를 반환해요. 변수가 없을 수 있는 조건부 로직에 유용해요. |
|
len(value_src) |
문자열 길이를 구해요. | |
isEmpty(value_src) |
문자열이 비어 있는지 확인해요. len(value_src) == 0과 같아요. |
|
substring(value_src, startIndex, endIndex) |
부분 문자열을 구해요. | |
startsWith(value_src, string_literal) |
문자열이 주어진 문자열 리터럴로 시작하는지 확인해요. | |
endsWith(value_src, string_literal) |
문자열이 주어진 문자열 리터럴로 끝나는지 확인해요. | |
contains(value_src, string_literal) |
문자열이 문자열 리터럴을 포함하는지, 또는 컬렉션이 요소를 포함하는지 확인해요. | |
matches(value_src, string_literal) |
문자열이 문자열 리터럴로 제공된 정규식과 일치하는지 확인해요. |
컬렉션 연산 (Collection operations)
컬렉션(리스트, 맵 등)을 다룰 때 predicate에서 컨텍스트 변수를 사용해 반복 중 요소에 접근할 수 있어요. 자세한 내용은 컨텍스트 변수 섹션을 참고하세요.
다음 예시는 [1,2,3,4] 값을 가진 mySequence와 {"a": 1, "b": 2, "c": 3} 값을 가진 myMap이 있다고 가정해요:
| 연산 | 설명 | 예시 |
|---|---|---|
len(value_src) |
컬렉션 크기를 구해요. | |
isEmpty(value_src) |
컬렉션이 비어 있는지 확인해요. len(value_src) == 0과 같아요. |
|
[ i ], [ key ] |
순차 컨테이너에서는 i번째 항목을 반환해요(i는 정수여야 해요). 사전에서는 key에 해당하는 값을 반환해요(key는 사전의 키 타입과 일치해야 해요). 항목이 없으면 언어에 따라 오류가 발생하거나 null을 반환해요. |
|
any(value_src, {predicate}) |
컬렉션에서 주어진 predicate를 만족하는 요소가 하나 이상 있는지 확인해요. 순차 컨테이너에서는 @it 참조, 사전에서는 @key, @value로 현재 요소에 접근해요. |
|
all(value_src, {predicate}) |
컬렉션의 모든 요소가 지정된 predicate를 만족하는지 확인해요. 현재 요소는 @it 참조로 접근해요. |
|
filter(value_src, {predicate}) |
predicate를 사용해 컬렉션의 요소를 필터링해요. 현재 요소는 @it 참조로 접근해요. |
직접 조건 시험해 보기 (Try your own conditions)
이 대화형 시뮬레이터는 실제 환경에서 표현식 언어 문법을 실험해 볼 수 있게 도와줘요. 메서드 계측 시 조건이 데이터 캡처 여부에 어떤 영향을 주는지 보여줘요.
예시 중 하나를 선택하거나 "when" 필드에 표현식을 입력하고 "SIMULATE"를 클릭하면 조건에 따라 데이터가 캡처되는지 확인할 수 있어요.
이 예시에서 사용 가능한 변수:
loops:5로 하드코딩된 라우트 매개변수myString: 문자열"Hello, world!"mySequence: 정수 배열[1, 2, 3]myMap: 사전{"a": 1, "b": 2, "c": 3}i: 현재 루프 반복 인덱스
다음 예시를 시도해 보세요. 참고: 제품 사용 시 조건 평가와 변수 접근 패턴은 달라질 수 있어요.
@app.route('/hello_world/<int:loops>')
def hello_world(loops):
myString = "hello world"
mySequence = [1, 2, 3, 4]
myMap = {"a": 1, "b": 2, "c": 3}
for i in range(loops):
pass
return "OK", 200
curl http://example-app:80/hello_world/5