Dashboard กับทัวร์ Datadog UI
ไอเดียหลักในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียหลักในหนึ่งประโยค”ทุก view ใน Datadog — Infrastructure, Metrics Explorer, Logs Explorer, APM, Dashboards — ถูก filter และ scope ด้วย tag syntax เดียวกัน ดังนั้นพอรู้จัก env/service/version จากบทที่แล้ว คุณก็รู้วิธี navigate ทุกตัวไปแล้ว ตัว UI เองเรียนรู้ได้ดีที่สุดด้วยการใช้จริง (บทนี้เน้น docs มากกว่าการพิสูจน์หนัก ๆ แบบบทอื่น) แต่ JSON ของ dashboard/Notebook ข้างใต้มันคือ API shape จริง ปัจจุบัน พิสูจน์ด้านล่างกับ model datadog_api_client จริง
ที่ที่คุณจะดูข้อมูลจริง ๆ
หัวข้อที่มีชื่อว่า “ที่ที่คุณจะดูข้อมูลจริง ๆ”ห้า view นี้ครอบคลุมเกือบทุกอย่างที่ต้องทำในแต่ละวัน
- Infrastructure List / Host Map — host หรือ container ทุกตัวที่ Datadog รู้จัก เป็น list ที่ sort ได้ หรือ grid สีสัน (Host Map) ที่ระบายสีตาม metric ไหนก็ได้ (CPU, memory) และ filter ด้วย tag ได้
- Metrics Explorer — สร้าง graph แบบ ad-hoc จาก metric ไหนก็ได้ แบ่งตาม tag โดยไม่ต้อง commit เป็น dashboard ที่ save ไว้ — นี่คือที่ที่ไปตอบคำถาม “ตัวเลขนี้หน้าตาเป็นยังไงตอนนี้จริง ๆ”
- Logs Explorer — ค้นหาและ filter log event ที่ถูก index สร้าง facet จาก log attribute และ pivot ตรงจาก log line ไปยัง trace ของตัวเองได้ถ้าตั้งค่า trace injection ไว้แล้ว
- APM Traces / Services — list Services โชว์ทุกค่า tag
serviceที่ Datadog เห็น trace มา พร้อม latency/error/throughput แบบเห็นภาพรวมทันที ลงลึกเข้าไปใน service ตัวหนึ่งจะเห็น trace ของตัวเองและตำแหน่งของตัวเองใน service map - Dashboards — ชุด widget ที่คัดสรรและ save ไว้ สร้างครั้งเดียวแล้วทั้งทีมใช้ซ้ำได้
flowchart TD
Filter["Tag filter: env:prod service:orders-api"] --> Infra["Infrastructure List / Host Map"]
Filter --> Metrics["Metrics Explorer"]
Filter --> Logs["Logs Explorer"]
Filter --> APM["APM Traces / Services"]
Filter --> Dash["Dashboards"]
Dashboard แบบ ordered เทียบกับ free
หัวข้อที่มีชื่อว่า “Dashboard แบบ ordered เทียบกับ free”Datadog Dashboard มี layout สองแบบ และเลือกให้ถูกตั้งแต่แรกช่วยประหยัดงานทำซ้ำทีหลังได้เยอะ
- Ordered — widget stack ต่อกันอัตโนมัติตามลำดับที่เพิ่มเข้าไป จากบนลงล่าง คุณไม่ต้องจัดการตำแหน่ง pixel คุณจัดการแค่ list นี่คือ default ที่ถูกต้องสำหรับ dashboard ส่วนใหญ่ — สร้างเร็ว, จัดลำดับใหม่ง่าย และ reflow ได้สมเหตุสมผลบนทุกขนาดหน้าจอ
- Free — คุณวาง widget แต่ละตัวมือด้วยพิกัด
x,y,widthและheightที่ชัดเจน ทำให้ได้ layout ที่ fix และตั้งใจวางไว้แบบนั้น — มีประโยชน์กับ dashboard สไตล์ status-board ที่ตั้งใจให้ดูบนจอใหญ่ ที่การจัดกลุ่มด้วยสายตาสำคัญกว่าความสะดวกในการแก้ไข
// A widget on a free dashboard carries explicit layout coordinates{ "definition": { "type": "timeseries", "title": "orders-api error rate" }, "layout": { "x": 0, "y": 0, "width": 6, "height": 3 }}// The same widget on an ordered dashboard has no layout block —// its position is just its position in the widgets array{ "definition": { "type": "timeseries", "title": "orders-api error rate" }}ถ้าไม่แน่ใจว่าต้องใช้แบบไหน เริ่มจาก ordered ก่อน — คุณขยาย widget หรือแยกเป็นสองตัวได้เสมอ และไม่ต้องมานั่งปรับพิกัดมือแค่เพื่อเพิ่ม graph อีกตัว
กายวิภาคของ dashboard JSON validate กับ model จริง
หัวข้อที่มีชื่อว่า “กายวิภาคของ dashboard JSON validate กับ model จริง”dashboard คือ JSON document ที่มี top-level field แบบแบนบวก array widgets — แต่ละ widget มี definition (widget ชนิดไหน query อะไร) และมี layout เฉพาะบน free dashboard เท่านั้น ตัวอย่าง shape จริงปัจจุบัน — widget สามชนิด, template variable, layout_type — validate ด้วย datadog_api_client.v1.model.dashboard.Dashboard(**data, _check_type=True):
{ "title": "orders-api overview", "description": "Error rate, request volume, and top endpoints for orders-api", "layout_type": "ordered", "template_variables": [ { "name": "env", "prefix": "env", "available_values": ["prod", "staging"], "default": "prod" }, { "name": "service", "prefix": "service", "available_values": ["orders-api"], "default": "orders-api" } ], "widgets": [ { "definition": { "type": "timeseries", "title": "orders-api error rate", "requests": [ { "response_format": "timeseries", "queries": [ { "data_source": "metrics", "name": "query1", "query": "sum:trace.http.request.errors{$env,$service}.as_count()" } ], "formulas": [{ "formula": "query1" }], "display_type": "line" } ] } }, { "definition": { "type": "query_value", "title": "orders-api request volume (5m)", "requests": [ { "response_format": "scalar", "queries": [ { "data_source": "metrics", "name": "query1", "query": "sum:trace.http.request.hits{$env,$service}.as_count()" } ], "formulas": [{ "formula": "query1" }] } ] } }, { "definition": { "type": "toplist", "title": "Top endpoints by error count", "requests": [ { "response_format": "scalar", "queries": [ { "data_source": "metrics", "name": "query1", "query": "sum:trace.http.request.errors{$env,$service} by {resource_name}.as_count()" } ], "formulas": [{ "formula": "query1" }] } ] } } ]}$ python3 -c "import jsonfrom datadog_api_client.v1.model.dashboard import Dashboarddata = json.load(open('orders-api-overview.json'))Dashboard(**data, _check_type=True)print('OK: valid')"OK: validสองเรื่องที่ควรพูดถึงเรื่อง query shape ยืนยันด้วยการ introspect model จริงที่ติดตั้งอยู่ ไม่ใช่การเดา: array queries ของ widget request เก็บ object data_source/name/query ต่อ data source ("data_source": "metrics" สำหรับ metric query) และ formulas เป็น array แยกที่ reference name ของ query เหล่านั้น ({"formula": "query1"}) — นี่คือ shape formulas-and-functions ปัจจุบัน shape เดียวกับที่ review เจอว่าผิดใน Terraform resource datadog_dashboard ของคอร์สนี้ (fix นั้นอยู่ที่ datadog-as-code-with-terraform ไม่ใช่ที่นี่ แต่ API shape ข้างใต้เหมือนกันเป๊ะไม่ว่าจะเขียนเป็น Terraform HCL หรือ JSON เขียนมือ) model ยัง รับ field แบบเก่า "q": "sum:trace...{...}" string เปล่า ๆ บน request แทน queries/formulas ได้ด้วย — ทั้งคู่เป็น field จริง valid บน model เดียวกัน — แต่ queries/formulas คือ shape ปัจจุบันที่แนะนำ และเป็นตัวที่บทนี้ใช้ตลอด
error จริงที่จับได้: dashboard ที่ขาด layout_type
หัวข้อที่มีชื่อว่า “error จริงที่จับได้: dashboard ที่ขาด layout_type”layout_type ไม่ใช่ optional — มันคือ constructor argument ที่ required จริงบน model จริง และ dashboard JSON ที่ copy มาจากตัวอย่างที่โชว์แค่ array widgets (การละเว้นแบบที่ AI-generated code มีโอกาสสูง) จะ fail ทันทีและชัดเจน:
// @expect-error dashboards/orders-api-overview-broken.json -- missing required layout_type{ "title": "orders-api overview", "widgets": []}$ python3 -c "from datadog_api_client.v1.model.dashboard import DashboardDashboard(title='orders-api overview', widgets=[], _check_type=True)"TypeError: Dashboard.__init__() missing 1 required positional argument: 'layout_type'Notebooks
หัวข้อที่มีชื่อว่า “Notebooks”Notebooks คือทางเลือกที่เบากว่า Dashboard สำหรับงานคนละแบบ — เล่าเรื่อง ไม่ใช่ดูแล status board แบบ live Notebook ผสม graph, log query และ markdown ข้อความอิสระไว้ในเอกสารเดียวที่ scroll ได้ — เป็นที่ธรรมชาติสำหรับเขียน timeline ของ incident (“นี่คือ graph latency ตอนที่พุ่ง, นี่คือ deploy marker, นี่คือสิ่งที่สรุปได้”), postmortem หรือการสืบสวนแบบครั้งเดียวที่อยากส่งต่อให้เพื่อนร่วมทีม ต่างจาก Dashboard ตรงที่ Notebook ตั้งใจให้อ่านจากบนลงล่างครั้งเดียว ไม่ใช่เหลือบดูซ้ำ ๆ
Notebook JSON และเรื่องน่าแปลกใจของชื่อ model
หัวข้อที่มีชื่อว่า “Notebook JSON และเรื่องน่าแปลกใจของชื่อ model”payload สำหรับสร้าง Notebook คือ envelope ที่ nested: {"data": {"type": "notebooks", "attributes": {"name", "time", "cells": [...]}}} ข้อเท็จจริงจริงที่ควรพูดถึงตรง ๆ ยืนยันด้วยการค้นใน package datadog_api_client ที่ติดตั้งจริง ไม่ใช่การสมมติ: Notebooks มีอยู่แค่ใน module v1 เท่านั้น — ไม่มี datadog_api_client.v2.model.notebook* เลย ต่างจาก Dashboard/Monitor/SLO ที่คอร์สนี้ validate ด้วย ถ้าคุณเขียนโค้ดเรื่อง Notebooks v1 ไม่ใช่ fallback แบบเก่าตรงนี้ มันคือทางเลือกเดียว model ระดับบนสุดคือ NotebookCreateRequest validate แบบเดียวกับตัวอย่าง Dashboard ด้านบน:
// notebooks/orders-api-incident.json -- not a harness-collected directory// (dashboards/monitors/slos/service-catalog/logs-pipelines only); validated// by hand against datadog_api_client.v1.model.notebook_create_request below.{ "data": { "type": "notebooks", "attributes": { "name": "orders-api incident 2026-09-29", "time": { "live_span": "4h" }, "cells": [ { "type": "notebook_cells", "attributes": { "definition": { "type": "markdown", "text": "## orders-api latency spike\n\nTimeline of the incident and what we concluded." } } }, { "type": "notebook_cells", "attributes": { "definition": { "type": "timeseries", "title": "orders-api error rate", "requests": [ { "response_format": "timeseries", "queries": [ { "data_source": "metrics", "name": "query1", "query": "sum:trace.http.request.errors{service:orders-api}.as_count()" } ], "formulas": [{ "formula": "query1" }], "display_type": "line" } ] }, "time": { "live_span": "4h" } } } ] } }}$ python3 -c "import jsonfrom datadog_api_client.v1.model.notebook_create_request import NotebookCreateRequestdata = json.load(open('orders-api-incident.json'))NotebookCreateRequest(**data, _check_type=True)print('OK: valid')"OK: validcell ของ Notebook ใช้ shape definition ของ widget เดียวกันเป๊ะกับ widget ของ Dashboard (cell timeseries ด้านบนมี structure requests/queries/formulas เหมือนกับตัวอย่าง Dashboard เป๊ะ) — cell markdown คือส่วนเสริมเฉพาะของ Notebook เพราะการเล่าเรื่องต้องมี prose คั่นระหว่าง graph
Tag ชุดเดียวกัน ทุก view
หัวข้อที่มีชื่อว่า “Tag ชุดเดียวกัน ทุก view”เหตุผลที่ทุกอย่างนี้เชื่อมกันได้ — Infrastructure, Metrics Explorer, Logs Explorer, APM และ Dashboards ทั้งหมดรับ tag filter syntax เดียวกันเป๊ะ — env:prod, service:orders-api, version:1.4.2 รวมกับ AND/OR ตามต้องการ ตั้งค่า unified service tagging ให้ถูกต้อง (บทที่แล้ว) แล้ว filter สามค่าเดียวกันนั้นจะ narrow ทุก view เหล่านี้ลงเหลือ “deployable unit ตัวนี้ environment นี้ release นี้” — นั่นคือเหตุผลทั้งหมดที่คอร์สนี้ใช้เวลาทั้งบทสอนเรื่อง tagging ก่อนจะแตะ dashboard เลยด้วยซ้ำ
Reading AI-generated code
หัวข้อที่มีชื่อว่า “Reading AI-generated code”🐛 หา bug ในโค้ดนี้
// AI comment: "Dashboard JSON for the orders-api overview"{"title": "orders-api overview","description": "Error rate and request volume for orders-api","widgets": [ { "definition": { "type": "timeseries", "title": "orders-api error rate", "requests": [ { "response_format": "timeseries", "queries": [ { "data_source": "metrics", "name": "query1", "query": "sum:trace.http.request.errors{service:orders-api}.as_count()" } ], "formulas": [{ "formula": "query1" }] } ] } }]}เฉลย
ตัว widget เองคือ shape จริง ปัจจุบัน — queries/formulas, ชื่อ field ถูกต้อง, metric query syntax valid bug ที่พิสูจน์ด้วย model Dashboard จริงด้านบน: JSON นี้ขาด layout_type และมันไม่ใช่ field optional ที่มี default สมเหตุสมผล — Python client จริงโยน TypeError: Dashboard.__init__() missing 1 required positional argument: 'layout_type' ทันที ตัวอย่าง dashboard JSON จำนวนมากที่ลอยอยู่ทั่วไป (รวมถึงตัวที่ training data ของ AI ถูกสร้างมาจาก) โชว์แค่ array widgets แยกเดี่ยว ๆ ในฐานะ “ส่วนที่น่าสนใจ” ซึ่งเป็นเหตุผลตรง ๆ ว่าทำไมการละเว้นนี้ถึงหลุดรอดไปได้ วิธีแก้คือบรรทัดเดียว "layout_type": "ordered" (หรือ "free" พร้อม block layout ที่ตรงกันบนทุก widget) แต่ถ้าไม่มีมัน payload จะถูก reject ก่อนที่ Datadog จะดู widgets ด้วยซ้ำ
Mental Model
หัวข้อที่มีชื่อว่า “Mental Model”ลองนึกภาพ JSON ของ Dashboard เป็น ผังที่นั่งบวกสคริปต์สำหรับแต่ละที่นั่ง layout_type ตัดสินว่าสถานที่จะจัดที่นั่งเป็นแถวอัตโนมัติ (ordered) หรือคุณวางเก้าอี้แต่ละตัวมือด้วยพิกัด (free) — พิสูจน์ด้านบน สถานที่ปฏิเสธที่จะเปิดเลยถ้าไม่รู้ว่าแบบไหน definition ของแต่ละ widget คือสคริปต์ของที่นั่งนั้น — จะพูดอะไร (queries, data_source: metrics, query string จริง) และพูดยังไง (formulas รวม query ที่ตั้งชื่อไว้หนึ่งตัวหรือมากกว่าเป็นสิ่งที่แสดงจริง) cell ของ Notebook คือ format สคริปต์เดียวกัน แค่แทรกด้วยการบรรยายธรรมดา (cell markdown) แทนที่จะเป็น graph ทุกที่นั่ง
Trade-offs
หัวข้อที่มีชื่อว่า “Trade-offs”- Layout แบบ ordered เทียบกับ free — ordered แทบไม่ต้องดูแลเลย (เพิ่ม widget มันก็โผล่ท้าย list) แต่จัดกลุ่มด้วยสายตาแบบตั้งใจนอกเหนือจากลำดับเรียงเส้นตรงไม่ได้; free ให้ควบคุม pixel เต็มที่สำหรับ layout แบบ status-board แลกกับการแก้ไขในอนาคตทุกครั้งต้องคำนวณพิกัด
qstring เปล่า ๆ เทียบกับqueries/formulas— พิสูจน์ด้านบน ทั้งคู่เป็น field จริง valid บน widget-request model เดียวกัน;qเขียนมือสั้นกว่าสำหรับ query เดี่ยวง่าย ๆ,queries/formulasคือสิ่งที่ support การรวมหลาย query ด้วยคณิตศาสตร์ (จุดประสงค์ทั้งหมดของ “formulas and functions”) และเป็น shape ที่คอร์สนี้, docs API และตัว UI เองสร้างให้ในปัจจุบัน- Dashboard เทียบกับ Notebook สำหรับ widget ข้างใต้เดียวกัน — พิสูจน์ด้านบน cell
timeseriesของ Notebook กับ widgettimeseriesของ Dashboard ใช้ shaperequests/queries/formulasเหมือนกันเป๊ะ ดังนั้นทักษะเขียน query ย้ายไปมาได้เต็มที่ ความต่างคือเชิง structure ล้วน ๆ (grid ที่ live ใช้ซ้ำได้ เทียบกับเอกสารเส้นตรงที่บรรยาย) ไม่ใช่ความต่างด้านความสามารถของ query
Common Misconceptions
หัวข้อที่มีชื่อว่า “Common Misconceptions”- “dashboard JSON แค่ต้องมี title กับ array widgets” ผิด — พิสูจน์ด้านบน:
layout_typeคือ constructor argument ที่ required จริงบน modelDashboardจริง และการละเว้นมันคือTypeErrorจริงทันที ไม่ใช่ค่าที่ default ให้เงียบ ๆ - “query format ของ widget ปัจจุบันคือ query string เปล่า ๆ เหมือนที่ bug ของ Terraform
datadog_dashboardเก่าใช้” ผิด — พิสูจน์ด้านบนด้วยการ inspect model จริง: shape ปัจจุบันที่แนะนำคือqueries(array ของ query definition ที่ตั้งชื่อและมี data source) บวกformulas(reference ชื่อเหล่านั้น)qstring เปล่า ๆ ยัง valid บน model แต่เป็น shape แบบเก่า ไม่ใช่ตัวที่บทนี้ (หรือบท Terraform ที่แก้แล้ว) ใช้ - “Notebooks มี v2 API model แยกของตัวเอง เหมือน Dashboards กับ Monitors” ผิด — ยืนยันด้วยการค้นใน client ที่ติดตั้งจริง: Notebooks มีอยู่แค่ใน
datadog_api_client.v1ไม่มี v2 เทียบเท่าเลย - “cell graph ของ Notebook ใช้ query format คนละแบบกับ widget ของ Dashboard เลย” ผิด — พิสูจน์ด้านบน:
definitionของ celltimeseriesใน Notebook มี structure เหมือนกันเป๊ะกับdefinitionของ widgettimeseriesใน Dashboard ลงไปถึง fieldqueries/formulasเดียวกัน