Skip to content

TraceFlagControl

<caos-trace-flag-control>

the trace flags in force, with their expiry and levels editable in the row

May be placed on a page inside an app.

Name Attribute Description Type Default Required
flags property only The flags in force: { id, subject, subjectType?, level, expiresAt? }[]. expiresAt absent means NO EXPIRY WAS STATED, which is not the same as “never” and is counted on its own. json empty list Optional
now now, markup only The instant expiry is judged against — an epoch number or a parseable timestamp. An INPUT rather than a call to the clock, so what this component says about expiry is a function of what it was given. Absent falls back to the real clock, which is what an ordinary placement wants. datetime the real clock Optional
readonly readonly, markup only Draw the levels and expiries as text rather than controls, for somebody who may look but not change. The remove control goes with them. boolean false Optional
search search, markup only Narrows by subject, subject type or level. text none declared Optional
sortKey sort-key, markup only Which column orders the rows. text — one of subject, level, expiresAt subject Optional
sortDirection sort-direction, markup only Which way. A flag with no stated expiry sorts last in both directions — it is not the soonest to go and not the furthest away, it is unknown. text — one of asc, desc asc Optional
emptyText empty-text, markup only What to say with no flags at all. The default states the consequence, not the absence. text No trace flags — nothing is being recorded. Optional
Name When it fires What it carries
caos-trace-change A level or an expiry is changed in the grid. Raised per change, never batched. { id, level? , expiresAt? } — only what moved.
caos-trace-remove A row’s Remove control is pressed. { id }.

Not documented yet — this piece has not said.

Not documented yet — this piece has not said.

Not documented yet — this piece has not said.

Name Type What it tells you
active CaosTraceFlag[] The flags still recording.
expired CaosTraceFlag[] The flags that have stopped. Never counted with the active ones.
now number The instant expiry is being judged against.
visibleFlags CaosTraceFlag[] The flags surviving the search, in order.
Part Which piece of it When it is there
::part(control) The outer column. Always
::part(summary) The “N recording · M expired” line. Always
::part(search) The search box. Always
::part(table) The composed data table. Always
::part(level) A row’s level control. Always
::part(expires) A row’s expiry control. Always
::part(state) A row’s recording/expired text. Always
::part(remove) A row’s remove control. readonly is not set.

Before reproducing a problem, and whenever the answer to “why is there no log” might be that nothing was recording.

  • LogList — the flags are set and the question is which log to read.
  • DataTable — the rows are not trace flags. This one computes expiry against a clock and says what that means in words.

Every in-grid control carries an accessible name naming the flag it belongs to — “Logging level for jrivera (User)” — because a grid of unlabelled dropdowns is what a screen reader otherwise finds. Expiry is stated as WORDS on the row (“expired — not recording”), never as a date the reader must compare to today. The summary is a role="status" live region and, with no flags at all, says “Nothing is being recorded” rather than reporting an empty list neutrally.

The distinction the component exists for. The expired flag says so in words on its own row and is counted apart in the summary, rather than sitting there looking live.

{
"id": "example",
"section": "One recording, one expired",
"columns": 1,
"items": [
{
"id": "trace_flag_control_1",
"type": "component",
"key": "trace_flag_control",
"inputs": {
"now": "2026-09-18T16:00:00Z",
"flags": [
{
"id": "tf1",
"subject": "jrivera",
"subjectType": "User",
"level": "FINEST",
"expiresAt": "2026-09-18T18:00:00Z"
},
{
"id": "tf2",
"subject": "integration.user",
"subjectType": "User",
"level": "DEBUG",
"expiresAt": "2026-09-18T09:00:00Z"
},
{
"id": "tf3",
"subject": "BillingService",
"subjectType": "Class",
"level": "INFO"
}
]
}
}
]
}
<caos-trace-flag-control id="traceFlagControl1" now="2026-09-18T16:00:00Z"></caos-trace-flag-control>
// What an attribute cannot hold, set as a property — the same values the preview is drawn with.
const traceFlagControl1 = document.getElementById('traceFlagControl1');
traceFlagControl1.flags = [
{
"id": "tf1",
"subject": "jrivera",
"subjectType": "User",
"level": "FINEST",
"expiresAt": "2026-09-18T18:00:00Z"
},
{
"id": "tf2",
"subject": "integration.user",
"subjectType": "User",
"level": "DEBUG",
"expiresAt": "2026-09-18T09:00:00Z"
},
{
"id": "tf3",
"subject": "BillingService",
"subjectType": "Class",
"level": "INFO"
}
];

The dangerous empty state, said as a consequence rather than as an absence — it is the answer to “why is there no log” that people otherwise spend an afternoon on.

{
"id": "example",
"section": "Nothing is being recorded",
"columns": 1,
"items": [
{
"id": "trace_flag_control_1",
"type": "component",
"key": "trace_flag_control",
"inputs": {
"flags": []
}
}
]
}
<caos-trace-flag-control id="traceFlagControl1"></caos-trace-flag-control>
// What an attribute cannot hold, set as a property — the same values the preview is drawn with.
const traceFlagControl1 = document.getElementById('traceFlagControl1');
traceFlagControl1.flags = [];

The levels and expiries as text, and no remove control — for somebody without the permission.

{
"id": "example",
"section": "Look but not change",
"columns": 1,
"items": [
{
"id": "trace_flag_control_1",
"type": "component",
"key": "trace_flag_control",
"inputs": {
"readonly": true,
"now": "2026-09-18T16:00:00Z",
"flags": [
{
"id": "tf1",
"subject": "jrivera",
"subjectType": "User",
"level": "FINEST",
"expiresAt": "2026-09-18T18:00:00Z"
}
]
}
}
]
}
<caos-trace-flag-control id="traceFlagControl1" readonly now="2026-09-18T16:00:00Z"></caos-trace-flag-control>
// What an attribute cannot hold, set as a property — the same values the preview is drawn with.
const traceFlagControl1 = document.getElementById('traceFlagControl1');
traceFlagControl1.flags = [
{
"id": "tf1",
"subject": "jrivera",
"subjectType": "User",
"level": "FINEST",
"expiresAt": "2026-09-18T18:00:00Z"
}
];