{
  "topic": "admin",
  "path": [
    "admin"
  ],
  "title": "admin — runtime-switchable admin endpoints",
  "synopsis": "Both endpoint families require `ROLE_ADMIN` on the JWT and update process-local state atomically. State is **not** propagated across nodes; multi-node deployments must hit each node's endpoint separately.",
  "body": "# admin\n\n## NAME\n\nadmin — runtime-switchable controls exposed on the main API listener.\n\n## SYNOPSIS\n\n```\nGET  /api/admin/log-level\nPOST /api/admin/log-level\nGET  /api/admin/trace-sampler\nPOST /api/admin/trace-sampler\n```\n\n## DESCRIPTION\n\nBoth endpoint families require `ROLE_ADMIN` on the JWT and update process-local state atomically. State is **not** propagated across nodes; multi-node deployments must hit each node's endpoint separately.\n\n## ENDPOINTS\n\n### log-level\n\n`GET /api/admin/log-level` returns the current effective log level as JSON:\n\n```\n{\"level\": \"info\"}\n```\n\n`POST /api/admin/log-level` changes the level atomically. Request body: `{\"level\": \"<level>\"}`. Response: `{\"level\": \"<new>\", \"previous\": \"<old>\"}`. Valid values: `debug`, `info`, `warn`, `error`.\n\n### trace-sampler\n\n`GET /api/admin/trace-sampler` returns the current OpenTelemetry sampler configuration:\n\n```\n{\"sampler\": \"ratio\", \"ratio\": 0.1, \"parent_based\": true}\n```\n\n`POST /api/admin/trace-sampler` changes the sampler atomically. Body shape mirrors the GET response. Valid `sampler` values: `always`, `never`, `ratio`. When `sampler` is `ratio`, `ratio` must be a float in `(0, 1]`. Use `sampler: never` for zero sampling — `ratio: 0` is rejected.\n\n## EXAMPLES\n\n```\n# Read current log level\ncurl -H \"Authorization: Bearer $TOKEN\" \\\n  http://localhost:8080/api/admin/log-level\n\n# Switch to debug\ncurl -X POST -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"level\":\"debug\"}' \\\n  http://localhost:8080/api/admin/log-level\n\n# Sample 10% of traces\ncurl -X POST -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"sampler\":\"ratio\",\"ratio\":0.1}' \\\n  http://localhost:8080/api/admin/trace-sampler\n\n# Force 100% sampling on this node regardless of upstream\ncurl -X POST -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"sampler\":\"always\",\"parent_based\":false}' \\\n  http://localhost:8080/api/admin/trace-sampler\n\n# Disable local sampling (still honors upstream-sampled traceparent; set parent_based:false to override)\ncurl -X POST -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"sampler\":\"never\"}' \\\n  http://localhost:8080/api/admin/trace-sampler\n```\n\n## NOTES\n\n- `parent_based` defaults to `true` and respects upstream sampling decisions in the `traceparent` header. With `parent_based: true`, an upstream \"do not sample\" overrides this node's `sampler: always`. This is standard OpenTelemetry `ParentBased` semantics and is usually correct for distributed-trace integrity. Set `parent_based: false` to override.\n- The initial sampler at process start is seeded from the standard OpenTelemetry env vars `OTEL_TRACES_SAMPLER` and `OTEL_TRACES_SAMPLER_ARG`. Supported values are the six standard combinations from the OTel spec (`always_on`, `always_off`, `traceidratio`, and their `parentbased_` variants). The admin endpoint is a runtime override, not a replacement.\n- Sampler and log level are process-local. Each node has its own state; multi-node deployments need to hit each node's admin endpoint separately.\n- `/metrics` exposes application metrics (OIDC, and — with `CYODA_OTEL_ENABLED=true` — transaction/dispatch) in addition to Go runtime/process metrics. The OIDC metric family is present whenever IAM runs in `jwt` mode. See `telemetry` for authentication options and the full metric catalogue.\n\n## SEE ALSO\n\n- `run` — server lifecycle\n- `telemetry` — OpenTelemetry exporters and metrics\n- `config.auth` — JWT and `ROLE_ADMIN`\n",
  "sections": [
    {
      "name": "NAME",
      "body": "admin — runtime-switchable controls exposed on the main API listener."
    },
    {
      "name": "SYNOPSIS",
      "body": "```\nGET  /api/admin/log-level\nPOST /api/admin/log-level\nGET  /api/admin/trace-sampler\nPOST /api/admin/trace-sampler\n```"
    },
    {
      "name": "DESCRIPTION",
      "body": "Both endpoint families require `ROLE_ADMIN` on the JWT and update process-local state atomically. State is **not** propagated across nodes; multi-node deployments must hit each node's endpoint separately."
    },
    {
      "name": "ENDPOINTS",
      "body": "### log-level\n\n`GET /api/admin/log-level` returns the current effective log level as JSON:\n\n```\n{\"level\": \"info\"}\n```\n\n`POST /api/admin/log-level` changes the level atomically. Request body: `{\"level\": \"<level>\"}`. Response: `{\"level\": \"<new>\", \"previous\": \"<old>\"}`. Valid values: `debug`, `info`, `warn`, `error`.\n\n### trace-sampler\n\n`GET /api/admin/trace-sampler` returns the current OpenTelemetry sampler configuration:\n\n```\n{\"sampler\": \"ratio\", \"ratio\": 0.1, \"parent_based\": true}\n```\n\n`POST /api/admin/trace-sampler` changes the sampler atomically. Body shape mirrors the GET response. Valid `sampler` values: `always`, `never`, `ratio`. When `sampler` is `ratio`, `ratio` must be a float in `(0, 1]`. Use `sampler: never` for zero sampling — `ratio: 0` is rejected."
    },
    {
      "name": "EXAMPLES",
      "body": "```\n# Read current log level\ncurl -H \"Authorization: Bearer $TOKEN\" \\\n  http://localhost:8080/api/admin/log-level\n\n# Switch to debug\ncurl -X POST -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"level\":\"debug\"}' \\\n  http://localhost:8080/api/admin/log-level\n\n# Sample 10% of traces\ncurl -X POST -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"sampler\":\"ratio\",\"ratio\":0.1}' \\\n  http://localhost:8080/api/admin/trace-sampler\n\n# Force 100% sampling on this node regardless of upstream\ncurl -X POST -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"sampler\":\"always\",\"parent_based\":false}' \\\n  http://localhost:8080/api/admin/trace-sampler\n\n# Disable local sampling (still honors upstream-sampled traceparent; set parent_based:false to override)\ncurl -X POST -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"sampler\":\"never\"}' \\\n  http://localhost:8080/api/admin/trace-sampler\n```"
    },
    {
      "name": "NOTES",
      "body": "- `parent_based` defaults to `true` and respects upstream sampling decisions in the `traceparent` header. With `parent_based: true`, an upstream \"do not sample\" overrides this node's `sampler: always`. This is standard OpenTelemetry `ParentBased` semantics and is usually correct for distributed-trace integrity. Set `parent_based: false` to override.\n- The initial sampler at process start is seeded from the standard OpenTelemetry env vars `OTEL_TRACES_SAMPLER` and `OTEL_TRACES_SAMPLER_ARG`. Supported values are the six standard combinations from the OTel spec (`always_on`, `always_off`, `traceidratio`, and their `parentbased_` variants). The admin endpoint is a runtime override, not a replacement.\n- Sampler and log level are process-local. Each node has its own state; multi-node deployments need to hit each node's admin endpoint separately.\n- `/metrics` exposes application metrics (OIDC, and — with `CYODA_OTEL_ENABLED=true` — transaction/dispatch) in addition to Go runtime/process metrics. The OIDC metric family is present whenever IAM runs in `jwt` mode. See `telemetry` for authentication options and the full metric catalogue."
    },
    {
      "name": "SEE ALSO",
      "body": "- `run` — server lifecycle\n- `telemetry` — OpenTelemetry exporters and metrics\n- `config.auth` — JWT and `ROLE_ADMIN`"
    }
  ],
  "see_also": [
    "run",
    "telemetry",
    "config.auth"
  ],
  "stability": "stable",
  "actions": []
}
