리포지토리는 도커(Docker) 컨테이너 내에서 실행되도록 설정된 다중 서비스 고 애플리케이션을 포함합니다. 샘플 앱은 기본 메모 앱과 일정 앱으로 구성되어 있으며 각각에 REST API가 포함되어 데이터를 추가하고 변경할 수 있습니다 docker-compose YAML 파일은 docker 디렉터리에 있습니다.
이 튜토리얼에서는 all-docker-compose.yaml 파일을 사용합니다. 파일은 메모 및 일정 애플리케이션과 Datadog 에이전트 모두에 대한 컨테이너를 빌드합니다.
샘플 애플리케이션 시작 및 실행
애플리케이션 컨테이너 빌드 실행:
docker-compose -f all-docker-compose.yaml build
컨테이너 시작:
docker-compose -f all-docker-compose.yaml up -d
docker ps 명령을 사용해 컨테이너가 실행되는지 확인합니다. 다음과 같은 콘텐츠를 확인할 수 있어야 합니다.
컨테이너 ID 이미지 명령 생성 상태 포트 이름
0a4704ebed09 docker-notes "./cmd/notes/notes" 1분 전 약 1분 0.0.0.0:8080->8080/tcp notes
9c428d7f7ad1 docker-calendar "./cmd/calendar/cale..." 1분 전 약 1분 0.0.0.0:9090->9090/tcp calendar
b2c2bafa6b36 gcr.io/datadoghq/agent:latest "/bin/entrypoint.sh" 1분 전 약 1분(비정상) 8125/udp, 8126/tcp datadog-ag
샘플 notes 애플리케이션은 기본 REST API로 메모리 내부 데이터베이스에 데이터를 보관합니다. curl을 사용하여 몇몇 API 요청을 전송합니다.
curl localhost:8080/notes
아직 데이터베이스에 아무 것도 없기 때문에 []을 반환합니다.
curl -X POST 'localhost:8080/notes?desc=hello'
hello 설명 및 1 ID 값과 함께 메모를 추가합니다. {"id":1,"description":"hello"}을 반환합니다.
curl localhost:8080/notes/1
1의 id 값을 포함한 메모를 반환합니다. {"id":1,"description":"hello"}
curl -X POST 'localhost:8080/notes?desc=otherNote'
otherNote 설명과 2 ID 값을 포함한 메모를 추가합니다. {"id":2,"description":"otherNote"}를 반환합니다.
curl localhost:8080/notes
데이터베이스 콘텐츠를 반환합니다. [{"id":1,"description":"hello"},{"id";2,"description":"otherNote"}]
더 많은 API 호출을 실행하여 작동 중인 애플리케이션을 확인합니다. 완료되면 컨테이너를 종료하고 제거합니다. 컨테이너가 제거되었는지 확인하세요.
docker-compose -f all-docker-compose.yaml down
docker-compose -f all-docker-compose.yaml rm
추적 활성화
다음으로 고 애플리케이션을 설정하여 추적을 활성화합니다. 에이전트가 컨테이너에서 실행되므로 아무 것도 설치할 필요가 없습니다.
추적 지원을 활성화하려면 apm-tutorial-golang/cmd/notes/main.go의 가져오기에서 주석을 제거합니다.
추적 라이브러리가 설치되었으므로 애플리케이션 컨테이너를 스핀업하고 트레이스 수신을 시작합니다. 다음 명령을 실행합니다.
docker-compose -f all-docker-compose.yaml build
docker-compose -f all-docker-compose.yaml up -d
트레이스 생성 및 수집을 시작하려면 make run을 사용해 다시 애플리케이션을 시작합니다.
터미널에서 지속적인 출력을 관찰하여 에이전트가 작동하고 있는지 확인할 수 있습니다. 혹은 Datadog에서 이벤트 탐색기를 열어 에이전트 시작 이벤트를 확인할 수 있습니다.
curl을 다시 사용해 애플리케이션에 요청 전송:
curl localhost:8080/notes
[]
curl -X POST 'localhost:8080/notes?desc=hello'
{"id":1,"description":"hello"}
curl localhost:8080/notes/1
{"id":1,"description":"hello"}
curl localhost:8080/notes
[{"id":1,"description":"hello"}]
잠시 기다린 다음 Datadog UI를 살펴보세요. APM > 트레이스로 이동합니다. 트레이스 목록은 다음과 같은 콘텐츠를 표시합니다.
데이터베이스(db) 및 notes 앱에 대한 입력 항목입니다. 트레이스 목록은 모든 스팬, 시작 시점, 스팬을 사용해 추적되는 리소스, 소요 시간을 표시합니다.
트레이스를 확인할 수 없는 경우, 트레이스 검색 필드의 모든 피터를 지웁니다(사용하지 않는 ENV 등 환경 변수에서 필터링하는 경우가 있습니다.).
트레이스 검사
트레이스 페이지에서 POST /notes 트레이스를 클릭하면 각 스팬 소요 시간 및 스팬 완료 전 발생한 기타 스팬을 표시하는 불꽃 그래프를 확인할 수 있습니다. 그래프 상단의 막대는 이전 화면에서 선택한 스팬입니다(이 경우 메모 애플리케이션에서 초기 입력 요소).
바의 너비는 완료되는 데 소요된 시간을 나타냅니다. 낮은 깊이의 막대는 높은 깊이의 막대 수명 동안 완료된 스팬을 나타냅니다.
POST 트레이스의 불꽃 그래프는 이와 비슷한 형태입니다.
GET /notes 트레이스는 이와 비슷한 형태입니다.
추적 설정
추적 라이브러리를 설정하여 Datadog가 전송하는 텔레메트리에 태그를 추가할 수 있습니다. 태그는 대시보드와 그래프에서 데이터를 그룹화 또는 필터링하고 이를 의미 있는 방법으로 표시할 수 있도록 지원합니다. 태그를 추가하려면, 애플리케이션 실행 시 환경 변수를 지정합니다. 프로젝트 Makefile는 환경 변수 DD_ENV, DD_SERVICE 및 DD_VERSION를 포함하며 해당 변수는 통합 서비스 태깅을 활성화하도록 설정되어 있습니다.
Datadog는 코드에 구현하면 자동 추적을 허용하고 완전한 지원을 제공하는 고 애플리케이션용 라이브러리를 보유하고 있습니다. cmd/notes/main.go 파일에서 go-chi, sql 및 http 라이브러리는 각각 해당되는 Datadog 라이브러리인 chitrace, sqltrace 및 httptrace에 연결되어 있습니다.
chitrace.WithServiceName("notes")를 사용하면 라이브러리가 추적하는 모든 요소가 서비스 이름 notes 아래에 있는지 확인합니다.
main.go 파일은 이러한 각 라이브러리에 대한 더 많은 구현 예시를 포함합니다. 라이브러리 확장 목록을 보려면 고 호환성 요구 사항을 참조하세요.
컨텍스트 포함 커스텀 트레이싱 사용
코드가 지원되는 라이브러리에 해당하지 않으면 수동으로 스팬을 생성할 수 있습니다.
notes/notesController.go에서 makeSpanMiddleware 함수 관련 코멘트를 제거합니다. 해당 함수는 제공된 이름의 스팬에서 요청을 래핑하는 미들웨어를 생성합니다. 이 함수를 사용하려면 다음 줄을 코멘트 아웃합니다.
notes/notesController.go
r.Get("/notes",nr.GetAllNotes)// GET /notesr.Post("/notes",nr.CreateNote)// POST /notesr.Get("/notes/{noteID}",nr.GetNoteByID)// GET /notes/123r.Put("/notes/{noteID}",nr.UpdateNoteByID)// PUT /notes/123r.Delete("/notes/{noteID}",nr.DeleteNoteByID)// DELETE /notes/123
다음 줄의 코멘트를 제거합니다.
notes/notesController.go
r.Get("/notes",makeSpanMiddleware("GetAllNotes",nr.GetAllNotes))// GET /notesr.Post("/notes",makeSpanMiddleware("CreateNote",nr.CreateNote))// POST /notesr.Get("/notes/{noteID}",makeSpanMiddleware("GetNote",nr.GetNoteByID))// GET /notes/123r.Put("/notes/{noteID}",makeSpanMiddleware("UpdateNote",nr.UpdateNoteByID))// PUT /notes/123r.Delete("/notes/{noteID}",makeSpanMiddleware("DeleteNote",nr.DeleteNoteByID))// DELETE /notes/123
다음 가져오기에 대한 코멘트도 제거합니다.
notes/notesController.go
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
샘플 애플리케이션에 커스텀 추적의 몇몇 예시가 있습니다. 여기 두어 개의 예시가 추가로 제공됩니다. 이러한 스팬을 활성화하려면 코멘트를 제거합니다.
doLongRunningProcess 함수는 상위 컨텍스트에서 하위 스팬을 생성합니다.
notes/notesHelper.go
funcdoLongRunningProcess(ctxcontext.Context){childSpan,ctx:=tracer.StartSpanFromContext(ctx,"traceMethod1")childSpan.SetTag(ext.ResourceName,"NotesHelper.doLongRunningProcess")deferchildSpan.Finish()time.Sleep(300*time.Millisecond)log.Println("Hello from the long running process in Notes")privateMethod1(ctx)}
privateMethod1 함수는 컨텍스트에서 완전히 별도의 서비스를 생성하는 것을 보여줍니다.
notes/notesHelper.go
funcprivateMethod1(ctxcontext.Context){childSpan,_:=tracer.StartSpanFromContext(ctx,"manualSpan1",tracer.SpanType("web"),tracer.ServiceName("noteshelper"),)childSpan.SetTag(ext.ResourceName,"privateMethod1")deferchildSpan.Finish()time.Sleep(30*time.Millisecond)log.Println("Hello from the custom privateMethod1 in Notes")}
단일 애플리케이션 추적은 좋은 시작이지만 추적의 진정한 가치는 서비스를 통한 요청의 흐름을 확인하는 데 있습니다. 이것을 _분산 추적_이라고 부릅니다.
샘플 프로젝트는 calendar로 불리는 두 번째 애플리케이션을 포함하며 애플리케이션이 호출되면 임의의 날짜를 반환합니다. 메모 애플리케이션의 POST 엔드포인트는 add_date란 이름의 두 번째 쿼리 파라미터를 포함합니다. y로 설정되면 메모 애플리케이션은 일정 애플리케이션을 호출에 메모에 추가할 날짜를 얻습니다.