ข้ามไปยังเนื้อหา

Verification tools

ไม่มีเครื่องมือด้านล่างที่ซ้อนกันสมบูรณ์ และไม่มีตัวไหนสมบูรณ์ด้วยตัวเอง บรรทัด Caught by ของ AI bug catalog ระบุสำหรับทั้ง 27 entry ว่าเครื่องมือตัวไหน (ถ้ามี) จะจับได้ — และหลาย entry ระบุแค่ agent status หรือไม่มีอะไร offline ทุก output ที่นี่เป็นของจริง: datadog/agent:7 = Agent 7.83.3 (container dd-reading-a, DD_API_KEY ปลอม, DD_DD_URL ชี้ 127.0.0.1 หรือ listener ในเครื่อง, ไม่มี traffic ไป Datadog), dd-trace 6.17.0, ddtrace 4.15.2, datadog-api-client 2.61.0, datadog Terraform provider 4.22.0 บน Terraform v1.16.4 (ไม่มี plan ไม่มี apply ไม่ตั้ง cloud credential) ทั้งหมดรันบน Mac เครื่องเดียว

flowchart TD
  F["Config file / code fence"] --> S["Shape and names<br/>(configcheck, tsc, terraform validate, model constructor)"]
  S --> V["Values and types<br/>(agent status, config dump, ApiTypeError)"]
  V --> R["Runtime behaviour<br/>(captured payloads, fake trace-agent, flush receiver)"]
  R --> M["Meaning and semantics<br/>(docs, review, the Datadog API)"]
เครื่องมือไหนมองเห็น layer ไหน

configcheck พิมพ์ทุก configuration ที่ Agent resolve ได้ และบล็อก Configuration errors สำหรับไฟล์ที่ parse ไม่ได้ มันต้องมี Agent ที่ รันอยู่ (คุยผ่าน command socket ของ Agent) ดังนั้น docker run --rm datadog/agent:7 agent configcheck จะล้มด้วย unable to read artifact: open auth_token: no such file or directory; ให้ start container รอราว 20–35 วินาทีบน Mac เครื่องนี้ แล้ว docker exec:

Terminal window
docker run -d --rm --name dd-reading-a \
-e DD_API_KEY=<your-api-key> -e DD_HOSTNAME=probe -e DD_DD_URL=http://127.0.0.1:1 \
-v "$PWD/conf.d:/etc/datadog-agent/conf.d" datadog/agent:7
sleep 30
docker exec dd-reading-a agent configcheck
=== Configuration errors ===
mysql: yaml: unmarshal errors:
line 4: cannot unmarshal !!map into []integration.RawMap
=== http_check check ===
Configuration provider: file
Configuration source: file:/etc/datadog-agent/conf.d/http_check.d/conf.yaml
Config for instance ID: http_check:checkout:85dc6c39d0e92c1b
name: checkout
timeout: five
url: http://checkout:8080/health
~
===

อ่าน output นี้ให้ละเอียด ไฟล์ mysql (instances: แบบ mapping, catalog entry 1) ถูกรายงาน ไฟล์ http_check ที่มี timeout: "five" (entry 4) ถูกพิมพ์เป็น configuration ปกติโดยไม่บ่น เพราะ ค่า ที่ผิด type เป็นเรื่องของ check ไม่ใช่ตัว loader ดังนั้น configcheck พิสูจน์แค่ “loader parse shape ได้” และไม่มีอย่างอื่น

จุดบอดที่วัดได้: agent configcheck คืน exit status 0 แม้มีบล็อก Configuration errors (configcheck exit=0 ข้างบน) step ใน CI ที่ดูแค่ exit code จะปล่อยไฟล์พังผ่านไป

🐛 หา bug ในโค้ดนี้

Terminal window
# CI: validate Agent integration config
docker exec dd-reading-a agent configcheck || exit 1
echo "agent config OK"
เฉลย

|| exit 1 ไม่เคยทำงาน: exit status ที่วัดได้คือ 0 สำหรับไฟล์ที่ configcheck เองติดป้าย Configuration errors และมันยังแสดงแค่ครึ่ง shape ของความจริง (entry 2, 3, 4 ผ่าน configcheck แล้วล้มใน agent status) ให้ grep output หาบล็อก error และ อ่าน status:

scripts/reading-datadog/agent-config-gate.sh
out=$(docker exec dd-reading-a agent configcheck 2>&1)
if printf '%s\n' "$out" | grep -q "Configuration errors"; then
printf '%s\n' "$out"
exit 1
fi
docker exec dd-reading-a agent status 2>&1 | grep -A20 -E "Config Errors|Loading Errors" && exit 1
echo "agent config OK"

agent status คือที่ที่จุดบอดของเครื่องมือก่อนหน้าปรากฏ มันแสดง Running Checks พร้อม [ERROR] ต่อ instance และ exception ข้างใต้ รวมถึงส่วน Config Errors และ Loading Errors ทุกอย่างด้านล่างมาจาก container เดียวกัน หลังจาก check รันอย่างน้อยหนึ่งครั้ง:

Config Errors
==============
mysql
-----
yaml: unmarshal errors:
line 4: cannot unmarshal !!map into []integration.RawMap
Loading Errors
==============
postgres
--------
Python Check Loader:
could not configure check instance for python check postgres: yaml: unmarshal errors:
line 3: cannot unmarshal !!str `env:prod` into []string
redis
-----
Python Check Loader:
unable to load check redis: ... No module named 'datadog_checks.redis' ...
http_check (13.1.0)
Instance ID: http_check:checkout:85dc6c39d0e92c1b [ERROR]
Error: Detected 1 error while loading configuration model `InstanceConfig`:
timeout
Input should be a valid number, unable to parse string as a number

มีสองข้อจำกัด ข้อแรก exit status ก็เป็น 0 ที่นี่เช่นกัน (status exit=0 ที่วัดได้) จึงเป็นเครื่องมือสำหรับอ่าน ไม่ใช่ gate; ต้อง parse เอา ข้อสอง check ที่เชื่อมต่อกับอะไรบางอย่าง (database, nginx status URL) จะแสดง [ERROR] ตอนรันถ้า host เข้าไม่ถึง — เหมือน catalog entry 5 (Failed to resolve 'nginx') — ซึ่งเป็นผลที่ใช้ได้สำหรับการรีวิว config เพราะ configuration ถูก load แล้ว agent status ยังพิมพ์ endpoint ซึ่งเป็นวิธีที่พิสูจน์ catalog entry 6 (DD_SITE เป็น URL):

$ docker exec dd-reading-a agent status | grep -n "process\."
https://process.https://api.datadoghq.com. - API Key ending with:

agent dogstatsd-stats และ receiver ในเครื่อง — custom metric กลายเป็นอะไรจริง ๆ

หัวข้อที่มีชื่อว่า “agent dogstatsd-stats และ receiver ในเครื่อง — custom metric กลายเป็นอะไรจริง ๆ”

หากต้องการเห็นว่า custom metric กลายเป็นอะไร ต้องมีอะไรรับ flush ของ Agent ให้ชี้ DD_DD_URL ไปที่ HTTP server เล็ก ๆ ในเครื่อง (ไม่มีอะไรถึง Datadog) ส่ง DogStatsD ผ่าน UDP จากในตัว container แล้วอ่านสิ่งที่มาถึง สองการตั้งค่าทำให้อ่านง่าย: DD_USE_V2_API_SERIES=false (body JSON ของ /api/v1/series แทน protobuf) และ DD_SERIALIZER_COMPRESSOR_KIND=zlib (compression เริ่มต้นของ serializer ไม่ใช่ zlib จึง receiver Python ธรรมดา parse body ไม่ได้)

datadog.yaml
dogstatsd_metrics_stats_enable: true
$ docker exec dd-reading-a agent dogstatsd-stats
Metric | Tags | Count | Last Seen
-----------------------------------------|----------------------|------------|---------------------
orders.bounded | env:prod plan:pro | 25 | ...
orders.bounded | env:prod plan:free | 25 | ...
checkout.latency_dist | env:prod | 4 | ...
checkout.latency_hist | env:prod | 4 | ...
orders.count | env:prod user_id:u10 | 1 | ...
orders.count | env:prod user_id:u41 | 1 | ...

การรันเดียวกันดักได้บน receiver:

POST /api/v1/series checkout.latency_hist.{avg,count,median,95percentile,max} (histogram)
POST /api/beta/sketches (protobuf) (distribution)
orders.count 50 series orders.bounded 2 series

ถ้าไม่เปิด dogstatsd_metrics_stats_enable คำสั่งจะตอบ Dogstatsd metrics stats not enabled in the Agent configuration นี่คือวิธีที่ catalog entry 17 และ 18 ถูกพิสูจน์ ข้อจำกัด: ต้องมี Agent ที่รันอยู่ และมันพิสูจน์ สิ่งที่ Agent เห็น ไม่ใช่สิ่งที่แอปตั้งใจส่ง

dd-trace พิมพ์บรรทัด DATADOG TRACER CONFIGURATION ตอนเริ่ม (เปิดเป็นค่า default) พร้อมสิ่งที่ resolve ได้จริง เปรียบเทียบสองการรันที่ต่างกันหนึ่ง key:

tracer.init({ service: 'probe', logInjection: false }) -> "log_injection_enabled":false
tracer.init({ service: 'probe', log_injection: false }) -> "log_injection_enabled":true
DD_ENV=Prod DD_SERVICE=Checkout DD_VERSION=1.0.0 -> "env":"Prod","service":"Checkout","dd_version":"1.0.0"
DD_TRACE_SAMPLE_RATE=0.1 -> "sample_rate":0.1

Type ตอบคำถามเรื่อง ชื่อ โดยไม่ต้องรันอะไร: tsc --noEmit กับ dd-trace/index.d.ts ปฏิเสธ log_injection (TS2561 ... Did you mean to write 'logInjection'?) และ agentUrl (TS2353) แต่รายงานแค่ key ที่ไม่รู้จักตัวแรกต่อ object literal และไม่ทำอะไรกับไฟล์ .js โหมด --options ของ harness ดึง key ของ TracerOptions จาก .d.ts เดียวกันและตรวจทุก key ในทุก fence tracer.init({...})

ทั้งสองไม่บอกเรื่อง ลำดับ Catalog entry 10 (init หลัง require('express')) พิสูจน์ด้วยการรันแอปกับ trace-agent ปลอม — http.createServer 10 บรรทัดบน 127.0.0.1:28126 ที่บันทึกชื่อ span ที่พบในแต่ละ PUT /v0.4/traces:

init first => express.request, http.request
init second => http.request, web.request

ddtrace.config เป็น object แบบ dynamic ดังนั้น list ของ key แบบ static ไม่เคยเป็นข้อสรุป วิธีที่เชื่อถือได้เพียงวิธีเดียวคือ getattr จริง:

>>> config.logs_injection
AttributeError: ... object has no attribute logs_injection, logs_injection is not a valid configuration
>>> config._logs_injection # DD_LOGS_INJECTION, default True
True
>>> sorted(inspect.signature(tracer.configure).parameters)
['apm_tracing_disabled', 'appsec_enabled', 'appsec_enabled_origin', 'compute_stats_enabled',
'context_provider', 'iast_enabled', 'trace_processors']

จุดบอด: การ เขียน ลง attribute ที่ไม่รู้จักสำเร็จ (config.logs_injection = False สร้าง attribute ธรรมดา) การ introspect จึงเป็นการตรวจฝั่งอ่าน — harness resolve ชื่อด้วย getattr จึง flag การเขียนด้วย Environment variable มาจาก dump ของ SUPPORTED_CONFIGURATIONS (DD_LOGS_INJECTION มี; DD_LOG_INJECTION และ DD_TRACE_ANALYTICS_ENABLED ไม่มีใน ddtrace 4.15.2)

Terminal window
export TF_PLUGIN_CACHE_DIR=~/.terraform.d/plugin-cache
terraform init -backend=false -input=false && terraform validate

provider block ที่ใช้ในทุก proof ที่นี่ — key ปลอม, validate = false เพื่อให้ provider ไม่เรียก API และไม่มี plan หรือ apply เลย:

# provider block used for every proof (the harness generates the same one)
terraform {
required_providers {
datadog = {
source = "DataDog/datadog"
version = "4.22.0"
}
}
}
provider "datadog" {
api_key = "<your-api-key>"
app_key = "<your-app-key>"
validate = false
}

สิ่งที่มันบอก จาก catalog: Unsupported argument, Unsupported block type ... Did you mean "template_variable"?, Incorrect attribute value type ... set of string required, but have string, Missing required argument สิ่งที่มันบอกไม่ได้: string ของ query เป็น query ที่ถูกต้องของ Datadog หรือไม่, permission.id เป็น ID หรือไม่, exclusion filter กว้างเกินไปหรือไม่ อีกคำสั่งหนึ่งช่วยให้มันเป็นเครื่องมือ อ่าน ที่ดีขึ้น:

$ terraform providers schema -json | jq '.provider_schemas[].resource_schemas.datadog_monitor.block.attributes.notify_no_data.description'
"A boolean indicating whether this monitor will notify when data stops reporting. Defaults to `false`."

บรรทัดเดียวนี้แก้ข้อสรุปในรีวิววางแผนที่ว่า default เป็น true ให้ถือ provider schema เป็นเอกสารที่ grep ได้ และระวังเรื่อง credential: shell ของนักพัฒนามักมี cloud credential จริง จึงควรรัน proof เหล่านี้ด้วย key ของ Datadog ปลอม ล้างตัวแปร cloud และไม่ plan หรือ apply เด็ดขาด

from datadog_api_client.v1.model.monitor import Monitor
Monitor(**data, _check_type=True)

ผลที่วัดได้ (2.61.0) กลุ่มที่ raise:

options.thresholds.critical="2" -> ApiTypeError: Invalid type for variable 'critical'. Required value type is float and passed type was str at ['options']['thresholds']['critical']
tags="env:prod" -> ApiTypeError: Invalid type for variable 'tags'. Required value type is list and passed type was str at ['tags']
missing query -> TypeError: Monitor.__init__() missing 1 required positional argument: 'query'

และกลุ่มที่ไม่ raise (แต่ละตัว OK (constructs)): type="metrics alert", timeframe="30days" ของ SLO, processor type attribute_remapper ของ pipeline, layout_type="grid" ของ dashboard, widget ที่ไม่มี type, query burn_rate ที่ไม่มี .short_window(), composite "12345 && not-an-id" signal ฝั่ง client ที่เข้มกว่าคือ deserializer:

from datadog_api_client import ApiClient, Configuration
obj = ApiClient(Configuration()).deserialize(json_text, (Monitor,), True)
obj._unparsed # True when an enum value or a oneOf did not match

_unparsed เป็น True ทุกกรณี enum/oneOf ข้างบน การตรวจ Service Catalog เป็นกลไกอื่น: validate กับ JSON Schema ที่เผยแพร่ใน github.com/DataDog/schema (apiVersion: v2 → 'v2' is not one of ['v3']) และมันยอมรับ key ใน spec ที่ไม่รู้จัก

tools/verify-snippets.mjs เก็บเฉพาะ fence ที่ บรรทัดแรกเป็น path comment (# datadog.yaml, # conf.d/<check>.d/conf.yaml, // monitors/<name>.json, # terraform/<name>.tf, // src/<name>.ts, …); บรรทัดแรกที่มี @expect-error คือความล้มเหลวที่ตั้งใจและถูกข้าม fence อื่นเป็น fragment และโหมด strict ไม่แตะ

$ npm run verify # = --options + --tf + --json
--options: [email protected] init/configure calls: 10 checked, 0 with unknown key(s)
[email protected] config.<x> refs: 0 checked, 0 unknown; tracer.configure(kw=) refs: 0 checked, 0 unknown
DD_* env var refs: 8 checked, 0 unknown, 0 deprecated
--tf: provider [email protected] -- 14 fence(s) validated, 0 failed
--json: [email protected] -- 8 fence(s) classified, 0 failed

แต่ละโหมดทำอะไรกับ fence ที่ เสีย — บทเรียน scratch ที่มี log_injection init, monitor tags = "env:prod", threshold critical แบบ string และ instances: mapping ในไฟล์ conf.d:

--options: [email protected] init/configure calls: 11 checked, 1 with unknown key(s)
ERROR ...:fence #1: tracer.init({...}) unknown key(s) [log_injection] ([email protected] TracerOptions)
--tf: provider [email protected] -- 15 fence(s) validated, 1 failed
ERROR ...:fence #2: line 7: Incorrect attribute value type -- Inappropriate value for attribute "tags": set of string required, but have string.
--json: [email protected] -- 9 fence(s) classified, 1 failed
ERROR ...:fence #3 (monitor): ApiTypeError: Invalid type for variable 'critical'. Required value type is float and passed type was str at ['options']['thresholds']['critical']
--agent: datadog/agent:7 configcheck -- 3 lesson group(s) checked, 0 failed

บรรทัดสุดท้ายสำคัญที่สุด --agent รายงาน 0 failed สำหรับ instances: mapping ทั้งที่ agent configcheck เองพิมพ์ Configuration errors harness ให้ group ล้มเฉพาะเมื่อ output ตรงกับ \bERROR\b หรือ is not valid แต่ข้อความจริงคือ unmarshal errors ใต้ Configuration errors พร้อม exit status 0 — ไม่ตรงทั้งคู่ นี่คือข้อจำกัดของ harness ที่พบระหว่างเขียนโมดูลนี้ (รายงานให้ผู้ประสานงานคอร์ส ไม่ได้แก้ที่นี่) จนกว่าจะขยาย pattern ให้ถือว่า --agent สีเขียวแปลว่า “Agent เริ่มและ parse อะไรบางอย่าง ได้” แล้วยืนยันด้วย grep "Configuration errors" ของคุณเอง (ดู Spot-the-bug ข้างบน)

โหมดอื่น:

โหมดพิสูจน์ต้นทุน
--optionsทุก key ของ tracer.init({...}) มีใน .d.ts ที่ pin; ทุก ddtrace.config.<x> resolve ได้; ทุกชื่อ DD_* อยู่ใน list ที่รองรับ (harness ไม่ flag DD_TRACE_SAMPLE_RATE; การอยู่ใน list ที่รองรับไม่ได้แปลว่า ddtrace 4.15.2 ทำตาม — catalog entry 13 แสดงว่ามันเป็น no-op เงียบ ๆ ใน Python)ราวหนึ่งวินาที
--tfterraform init + validate ต่อ fence กับ provider 4.22.0หลายวินาทีต่อ fence ต้องมี provider cache
--jsonconstructor ของ Monitor / Dashboard / SLO / LogsPipeline + JSON Schema ของ Service Catalogราวหนึ่งวินาที พลาด enum
--agentdatadog/agent:7 จริงเริ่มได้เมื่อ mount YAML ของคุณ~35 วินาทีต่อบทเรียน ต้องมี Docker ดูจุดบอดข้างบน
--k8skubectl --dry-run=server บน kind-verify-k8soptional ข้ามเมื่อไม่มี cluster
--self-testfixture ดี/เสียของ harness เอง (jsUnknownFound, tfBadFound, jsonBadFound, agentOk, … ทั้งหมด true)start container ราวหนึ่งนาที
  1. lint format ของไฟล์เอง (parse YAML/JSON/HCL) — ไม่มีอะไรที่เฉพาะ Datadog
  2. ชื่อและ shape: tsc --noEmit / harness --options, terraform validate, model constructor, agent configcheck
  3. ค่าและการ load: agent status (อ่านมัน), config dump ของ tracer, _unparsed
  4. พฤติกรรม: trace-agent ปลอม, receiver ของ flush ในเครื่อง
  5. ที่เหลือ — ความหมาย, ลำดับของ exclusion filter, ไวยากรณ์ burn-rate, ตำแหน่ง Autodiscovery — คือ URL ของ docs และ reviewer บอกไว้ตรง ๆ ใน review
  • แต่ละเครื่องมือตอบหนึ่งคำถาม configcheck: loader อ่าน shape ได้ไหม status: load และรันไหม Dump: ค่าไหนชนะ validate: schema รู้จักชื่อไหม Model: type ถูกไหม Harness: มีคนเอาทั้งหมดต่อเข้า CI หรือยัง
  • exit code ไม่ใช่สัญญาณ สองคำสั่งของ Agent คืน 0 ทั้งที่พิมพ์ error อ่าน output
  • เขียวมีขอบเขต เขียนขอบเขตไว้ข้างผลลัพธ์
  • ความเร็ว vs ความจริง --options/--json/--tf ใช้วินาที; --agent และ agent status หลังรันใช้นาที แต่เห็นสิ่งที่ตัวอื่นเห็นไม่ได้
  • key ปลอม vs ความสมจริง DD_API_KEY ปลอมและ receiver ในเครื่องทำให้ทุก proof ปลอดภัยและ offline; แต่แสดง response จริงของ intake, การ evaluate monitor จริง หรือ UI จริงไม่ได้
  • pin vs ปัจจุบัน harness pin dd-trace, ddtrace, client และ provider; คำตอบที่ pin ทำซ้ำได้แต่เก่าเมื่อ upgrade รัน probe ของ catalog ใหม่เมื่อ pin ขยับ
  • “agent configcheck คืน 0 แปลว่า config ไม่มีปัญหา” มันคืน 0 พร้อมบล็อก Configuration errors
  • “npm run verify ครอบคลุม Agent” มันครอบคลุม --options, --tf และ --json; Agent คือ --agent รันแยก พร้อมข้อจำกัดข้างบน
  • “การตรวจด้วย model คือ validator” มันคือ constructor ที่ตรวจ type ของ scalar และ argument ที่ required
  • “terraform validate คุยกับ Datadog” มันอ่าน schema ของ provider; provider block ตั้ง validate = false และไม่มี request ใดถูกส่ง
agent configcheck คืน exit status เท่าไรสำหรับไฟล์ conf.d ที่ instances: เป็น mapping บน Agent 7.83.3
ทำไมโหมด --agent ของ harness รายงาน '0 failed' สำหรับบทเรียน scratch ที่มี instances: mapping
คำสั่งไหนแสดงว่า timeout: "five" ผิด ทั้งที่ agent configcheck พิมพ์มันโดยไม่บ่น
คุณต้องรู้ว่า key ที่ไม่รู้จักที่ส่งให้ tracer.init({...}) ในไฟล์ .js มีผลหรือไม่ อะไรพิสูจน์ได้
Monitor(**data, _check_type=True) ต่างจาก ApiClient(Configuration()).deserialize(json, (Monitor,), True) อย่างไรกับ type: "metrics alert"
terraform validate ที่ provider block ตั้ง validate = false พิสูจน์อะไรเกี่ยวกับ permission { id = "logs_modify_indexes" }