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)"]
agent configcheck — shape ไม่ใช่ health
หัวข้อที่มีชื่อว่า “agent configcheck — shape ไม่ใช่ health”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:
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:7sleep 30docker 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: fileConfiguration source: file:/etc/datadog-agent/conf.d/http_check.d/conf.yamlConfig for instance ID: http_check:checkout:85dc6c39d0e92c1bname: checkouttimeout: fiveurl: 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 ในโค้ดนี้
# CI: validate Agent integration configdocker exec dd-reading-a agent configcheck || exit 1echo "agent config OK"เฉลย
|| exit 1 ไม่เคยทำงาน: exit status ที่วัดได้คือ 0 สำหรับไฟล์ที่ configcheck เองติดป้าย Configuration errors และมันยังแสดงแค่ครึ่ง shape ของความจริง (entry 2, 3, 4 ผ่าน configcheck แล้วล้มใน agent status) ให้ grep output หาบล็อก error และ อ่าน status:
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 1fidocker exec dd-reading-a agent status 2>&1 | grep -A20 -E "Config Errors|Loading Errors" && exit 1echo "agent config OK"agent status — check load ขึ้นไหม และรันไหม
หัวข้อที่มีชื่อว่า “agent status — check load ขึ้นไหม และรันไหม”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 ไม่ได้)
dogstatsd_metrics_stats_enable: true$ docker exec dd-reading-a agent dogstatsd-statsMetric | 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 เห็น ไม่ใช่สิ่งที่แอปตั้งใจส่ง
startup config dump ของ tracer และ .d.ts — ชื่อ option, ค่า และลำดับ
หัวข้อที่มีชื่อว่า “startup config dump ของ tracer และ .d.ts — ชื่อ option, ค่า และลำดับ”dd-trace พิมพ์บรรทัด DATADOG TRACER CONFIGURATION ตอนเริ่ม (เปิดเป็นค่า default) พร้อมสิ่งที่ resolve ได้จริง เปรียบเทียบสองการรันที่ต่างกันหนึ่ง key:
tracer.init({ service: 'probe', logInjection: false }) -> "log_injection_enabled":falsetracer.init({ service: 'probe', log_injection: false }) -> "log_injection_enabled":trueDD_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.1Type ตอบคำถามเรื่อง ชื่อ โดยไม่ต้องรันอะไร: 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.requestinit second => http.request, web.requestการ introspect ddtrace — attribute และ keyword argument ของจริง
หัวข้อที่มีชื่อว่า “การ introspect ddtrace — attribute และ keyword argument ของจริง”ddtrace.config เป็น object แบบ dynamic ดังนั้น list ของ key แบบ static ไม่เคยเป็นข้อสรุป วิธีที่เชื่อถือได้เพียงวิธีเดียวคือ getattr จริง:
>>> config.logs_injectionAttributeError: ... object has no attribute logs_injection, logs_injection is not a valid configuration>>> config._logs_injection # DD_LOGS_INJECTION, default TrueTrue>>> 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)
terraform validate — ชื่อ, block และ type เทียบกับ provider ที่ pin
หัวข้อที่มีชื่อว่า “terraform validate — ชื่อ, block และ type เทียบกับ provider ที่ pin”export TF_PLUGIN_CACHE_DIR=~/.terraform.d/plugin-cacheterraform init -backend=false -input=false && terraform validateprovider 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 เด็ดขาด
model ของ datadog-api-client — type และ field ที่ required ไม่ใช่ enum
หัวข้อที่มีชื่อว่า “model ของ datadog-api-client — type และ field ที่ required ไม่ใช่ enum”from datadog_api_client.v1.model.monitor import MonitorMonitor(**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, Configurationobj = 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 ที่ไม่รู้จัก
harness ของคอร์ส — npm run verify และโหมดต่าง ๆ
หัวข้อที่มีชื่อว่า “harness ของคอร์ส — npm run verify และโหมดต่าง ๆ”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) | ราวหนึ่งวินาที |
--tf | terraform init + validate ต่อ fence กับ provider 4.22.0 | หลายวินาทีต่อ fence ต้องมี provider cache |
--json | constructor ของ Monitor / Dashboard / SLO / LogsPipeline + JSON Schema ของ Service Catalog | ราวหนึ่งวินาที พลาด enum |
--agent | datadog/agent:7 จริงเริ่มได้เมื่อ mount YAML ของคุณ | ~35 วินาทีต่อบทเรียน ต้องมี Docker ดูจุดบอดข้างบน |
--k8s | kubectl --dry-run=server บน kind-verify-k8s | optional ข้ามเมื่อไม่มี cluster |
--self-test | fixture ดี/เสียของ harness เอง (jsUnknownFound, tfBadFound, jsonBadFound, agentOk, … ทั้งหมด true) | start container ราวหนึ่งนาที |
รันอะไร ตามลำดับไหน
หัวข้อที่มีชื่อว่า “รันอะไร ตามลำดับไหน”- lint format ของไฟล์เอง (parse YAML/JSON/HCL) — ไม่มีอะไรที่เฉพาะ Datadog
- ชื่อและ shape:
tsc --noEmit/ harness--options,terraform validate, model constructor,agent configcheck - ค่าและการ load:
agent status(อ่านมัน), config dump ของ tracer,_unparsed - พฤติกรรม: trace-agent ปลอม, receiver ของ flush ในเครื่อง
- ที่เหลือ — ความหมาย, ลำดับของ exclusion filter, ไวยากรณ์ burn-rate, ตำแหน่ง Autodiscovery — คือ URL ของ docs และ reviewer บอกไว้ตรง ๆ ใน review
Mental Model
หัวข้อที่มีชื่อว่า “Mental Model”- แต่ละเครื่องมือตอบหนึ่งคำถาม
configcheck: loader อ่าน shape ได้ไหมstatus: load และรันไหม Dump: ค่าไหนชนะvalidate: schema รู้จักชื่อไหม Model: type ถูกไหม Harness: มีคนเอาทั้งหมดต่อเข้า CI หรือยัง - exit code ไม่ใช่สัญญาณ สองคำสั่งของ Agent คืน
0ทั้งที่พิมพ์ error อ่าน output - เขียวมีขอบเขต เขียนขอบเขตไว้ข้างผลลัพธ์
Trade-offs
หัวข้อที่มีชื่อว่า “Trade-offs”- ความเร็ว 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 ขยับ
Common Misconceptions
หัวข้อที่มีชื่อว่า “Common Misconceptions”- “
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 ใดถูกส่ง