> ## Documentation Index
> Fetch the complete documentation index at: https://synthetiq.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Metrics reference

> Structured logging, metrics.json schema, and monitoring dashboard configuration

## Structured logging

Log custom events from the server using the `log()` function:

```typescript theme={null}
import { log } from '@synthetiq/app-framework/server';

log({
  source: 'app',
  type: 'task_completed',
  priority: task.priority,
  userId: ctx.userId,
  traceId: ctx.traceId,
});
```

Every log entry requires `source` and `type`. Beyond that, you can include any fields you want — these become available for log filtering and metric dimensioning. Logs are searchable in the monitoring dashboard at `/admin/monitoring/logs`.

## Client-side logging

Log events from the frontend using the `logs.ingest` tRPC procedure:

```typescript theme={null}
const trpc = getTrpc();

trpc.logs.ingest.mutate({
  type: 'button_clicked',
  traceId: getTraceId(),
  timestamp: Date.now(),
  data: {
    buttonId: 'export',
    page: '/tasks',
  },
});
```

| Field       | Type   | Required | Description                                         |
| ----------- | ------ | -------- | --------------------------------------------------- |
| `type`      | string | Yes      | Event type identifier                               |
| `traceId`   | string | Yes      | Trace ID from `getTraceId()`                        |
| `timestamp` | number | Yes      | `Date.now()` at time of event                       |
| `path`      | string | No       | Page path                                           |
| `method`    | string | No       | HTTP method                                         |
| `status`    | number | No       | Status code                                         |
| `data`      | object | No       | Custom fields for metric filtering and dimensioning |

The framework automatically sets `source: "app"` and attaches the authenticated user's ID.

## metrics.json schema

Defined at the app root. Configures how metrics are derived from log entries and how charts are rendered on the monitoring dashboard. Validated at build time.

```json theme={null}
{
  "metrics": [],
  "dimensions": {},
  "charts": []
}
```

## Metrics

Each metric definition derives a metric from matching log entries:

| Field        | Type             | Required | Description                                                                               |
| ------------ | ---------------- | -------- | ----------------------------------------------------------------------------------------- |
| `name`       | string           | Yes      | Metric name                                                                               |
| `unit`       | string           | Yes      | `Count`, `Milliseconds`, `Seconds`, or `Bytes`                                            |
| `value`      | number or string | Yes      | A literal number (e.g., `1`) or a log field name to read the value from (e.g., `"ms"`)    |
| `dimensions` | string\[]        | Yes      | Array of dimension keys to group by                                                       |
| `filter`     | object           | No       | Log field → array of accepted values. Only matching log entries contribute to this metric |

```json theme={null}
{
  "name": "TaskCompletions",
  "unit": "Count",
  "value": 1,
  "dimensions": ["priority"],
  "filter": { "type": ["task_completed"] }
}
```

## Dimensions

Dimensions define how metric values are grouped. Each dimension maps a log field to a set of labeled buckets:

| Field     | Type   | Required | Description                                              |
| --------- | ------ | -------- | -------------------------------------------------------- |
| `field`   | string | Yes      | The log field to read                                    |
| `buckets` | object | No       | Label → numeric range `[min, max]` or exact string match |

```json theme={null}
{
  "priority": {
    "field": "priority",
    "buckets": {
      "High": "high",
      "Medium": "medium",
      "Low": "low"
    }
  },
  "statusCategory": {
    "field": "status",
    "buckets": {
      "Success": [200, 399],
      "Warning": [400, 499],
      "Error": [500, 599]
    }
  }
}
```

Buckets bound cardinality — log values that don't match any bucket are excluded from that dimension.

## Charts

Each chart definition renders a chart on the monitoring dashboard:

| Field             | Type   | Required | Description                                                                                                        |
| ----------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------ |
| `title`           | string | Yes      | Chart title                                                                                                        |
| `metric`          | string | Yes      | Metric name to visualize                                                                                           |
| `stat`            | string | No       | Statistic type (see below). Defaults to `Sum` for Count, `Average` for other units                                 |
| `chartType`       | string | No       | `line` (default) or `bar`                                                                                          |
| `splitBy`         | string | No       | Dimension key to split series by. Bar charts with `splitBy` render as stacked bars                                 |
| `tab`             | string | No       | Dashboard tab name. Default is `application`. Use the same `tab` value to group charts together                    |
| `color`           | string | No       | Color hint (e.g., `"error"`)                                                                                       |
| `transform`       | object | No       | Transform the data (e.g., `{ "type": "percentage", "numerator": ["Error"], "denominator": ["Success", "Error"] }`) |
| `overlayMetrics`  | array  | No       | Additional metrics to overlay on the same chart (e.g., `[{ "metric": "WorkerCapacity", "label": "Capacity" }]`)    |
| `seriesStyles`    | object | No       | Per-series styling (e.g., `{ "Capacity": { "borderDash": [6, 3] } }`)                                              |
| `namespace`       | string | No       | CloudWatch namespace for infrastructure metrics (e.g., `"AWS/ECS"`)                                                |
| `fixedDimensions` | object | No       | Fixed CloudWatch dimension values for infrastructure metrics                                                       |
| `unit`            | string | No       | Display unit override (e.g., `"Percent"`)                                                                          |

## Stat types

| Stat          | Description                                                 |
| ------------- | ----------------------------------------------------------- |
| `Sum`         | Total value (default for `Count` unit)                      |
| `Average`     | Mean value (default for `Milliseconds`, `Seconds`, `Bytes`) |
| `Minimum`     | Lowest value                                                |
| `Maximum`     | Highest value                                               |
| `SampleCount` | Number of data points                                       |
| `p50`         | 50th percentile                                             |
| `p90`         | 90th percentile                                             |
| `p95`         | 95th percentile                                             |
| `p99`         | 99th percentile                                             |

## Built-in metrics

The framework ships with default metrics that require no configuration:

| Metric                | Unit         | Description                                      |
| --------------------- | ------------ | ------------------------------------------------ |
| `RequestCount`        | Count        | HTTP requests, service calls, and page views     |
| `Latency`             | Milliseconds | Request and service call duration                |
| `WorkflowJobCount`    | Count        | Workflow job events (started, completed, failed) |
| `WorkflowJobDuration` | Milliseconds | Workflow job execution time                      |
| `WorkflowStepCount`   | Count        | Workflow step events                             |
| `WorkerDemand`        | Count        | Current worker demand                            |
| `WorkerCapacity`      | Count        | Total worker capacity                            |

Default charts are included for request count by status, error rate, latency percentiles, workflow job status, and infrastructure metrics (CPU, memory, task count).

### Default metrics.json

Every scaffolded app includes the following `metrics.json`:

```json theme={null}
{
  "metrics": [
    {
      "name": "RequestCount",
      "unit": "Count",
      "value": 1,
      "dimensions": ["type", "statusCategory"],
      "filter": { "type": ["http_request", "service_call", "page_view"] }
    },
    {
      "name": "Latency",
      "unit": "Milliseconds",
      "value": "ms",
      "dimensions": ["type"],
      "filter": { "type": ["http_request", "service_call"] }
    },
    {
      "name": "WorkerDemand",
      "unit": "Count",
      "value": "demand",
      "dimensions": [],
      "filter": { "type": ["worker_scaling"] }
    },
    {
      "name": "WorkerCapacity",
      "unit": "Count",
      "value": "totalCapacity",
      "dimensions": [],
      "filter": { "type": ["worker_scaling"] }
    },
    {
      "name": "WorkflowJobCount",
      "unit": "Count",
      "value": 1,
      "dimensions": ["workflowEvent", "statusCategory"],
      "filter": { "type": ["workflow_job"] }
    },
    {
      "name": "WorkflowJobDuration",
      "unit": "Milliseconds",
      "value": "ms",
      "dimensions": ["workflowEvent"],
      "filter": { "type": ["workflow_job"] }
    },
    {
      "name": "WorkflowStepCount",
      "unit": "Count",
      "value": 1,
      "dimensions": ["workflowEvent", "statusCategory"],
      "filter": { "type": ["workflow_step"] }
    }
  ],
  "dimensions": {
    "type": {
      "field": "type",
      "buckets": {
        "HTTP Request": "http_request",
        "Service Call": "service_call",
        "Page View": "page_view",
        "Workflow Job": "workflow_job",
        "Workflow Step": "workflow_step"
      }
    },
    "statusCategory": {
      "field": "status",
      "buckets": {
        "Success": [200, 399],
        "Warning": [400, 499],
        "Error": [500, 599]
      }
    },
    "workflowEvent": {
      "field": "event",
      "buckets": {
        "Started": "started",
        "Completed": "completed",
        "Failed": "failed",
        "Retry": "retry"
      }
    }
  },
  "charts": [
    {
      "title": "Request Count by Status",
      "metric": "RequestCount",
      "stat": "Sum",
      "chartType": "bar",
      "splitBy": "statusCategory"
    },
    {
      "title": "Request Count by Type",
      "metric": "RequestCount",
      "stat": "Sum",
      "chartType": "line",
      "splitBy": "type"
    },
    {
      "title": "Error Rate",
      "metric": "RequestCount",
      "stat": "Sum",
      "chartType": "line",
      "splitBy": "statusCategory",
      "color": "error",
      "transform": {
        "type": "percentage",
        "numerator": ["Error"],
        "denominator": ["Success", "Warning", "Error"]
      }
    },
    {
      "title": "Average Latency by Type",
      "metric": "Latency",
      "stat": "Average",
      "chartType": "line",
      "splitBy": "type"
    },
    {
      "title": "P95 Latency by Type",
      "metric": "Latency",
      "stat": "p95",
      "chartType": "line",
      "splitBy": "type"
    },
    {
      "title": "Max Latency by Type",
      "metric": "Latency",
      "stat": "Maximum",
      "chartType": "line",
      "splitBy": "type"
    },
    {
      "title": "App CPU Utilization",
      "metric": "CPUUtilization",
      "stat": "Average",
      "chartType": "line",
      "unit": "Percent",
      "tab": "infrastructure",
      "namespace": "AWS/ECS",
      "fixedDimensions": { "ClusterName": "${CLUSTER_NAME}", "ServiceName": "${APP_SERVICE_NAME}" }
    },
    {
      "title": "App Memory Utilization",
      "metric": "MemoryUtilization",
      "stat": "Average",
      "chartType": "line",
      "unit": "Percent",
      "tab": "infrastructure",
      "namespace": "AWS/ECS",
      "fixedDimensions": { "ClusterName": "${CLUSTER_NAME}", "ServiceName": "${APP_SERVICE_NAME}" }
    },
    {
      "title": "App Task Count",
      "metric": "RunningTaskCount",
      "stat": "Average",
      "chartType": "line",
      "unit": "Count",
      "tab": "infrastructure",
      "namespace": "ECS/ContainerInsights",
      "fixedDimensions": { "ClusterName": "${CLUSTER_NAME}", "ServiceName": "${APP_SERVICE_NAME}" },
      "overlayMetrics": [{ "metric": "DesiredTaskCount", "label": "Desired" }],
      "seriesStyles": { "Desired": { "borderDash": [6, 3] } }
    },
    {
      "title": "Worker CPU Utilization",
      "metric": "CPUUtilization",
      "stat": "Average",
      "chartType": "line",
      "unit": "Percent",
      "tab": "infrastructure",
      "namespace": "AWS/ECS",
      "fixedDimensions": { "ClusterName": "${CLUSTER_NAME}", "ServiceName": "${WORKER_SERVICE_NAME}" }
    },
    {
      "title": "Worker Memory Utilization",
      "metric": "MemoryUtilization",
      "stat": "Average",
      "chartType": "line",
      "unit": "Percent",
      "tab": "infrastructure",
      "namespace": "AWS/ECS",
      "fixedDimensions": { "ClusterName": "${CLUSTER_NAME}", "ServiceName": "${WORKER_SERVICE_NAME}" }
    },
    {
      "title": "Worker Task Count",
      "metric": "RunningTaskCount",
      "stat": "Average",
      "chartType": "line",
      "unit": "Count",
      "tab": "infrastructure",
      "namespace": "ECS/ContainerInsights",
      "fixedDimensions": { "ClusterName": "${CLUSTER_NAME}", "ServiceName": "${WORKER_SERVICE_NAME}" },
      "overlayMetrics": [{ "metric": "DesiredTaskCount", "label": "Desired" }],
      "seriesStyles": { "Desired": { "borderDash": [6, 3] } }
    },
    {
      "title": "Worker Demand vs Capacity",
      "metric": "WorkerDemand",
      "stat": "Maximum",
      "chartType": "line",
      "unit": "Count",
      "tab": "infrastructure",
      "overlayMetrics": [{ "metric": "WorkerCapacity", "label": "Capacity" }],
      "seriesStyles": { "Capacity": { "borderDash": [6, 3] } }
    },
    {
      "title": "Workflow Jobs by Status",
      "metric": "WorkflowJobCount",
      "stat": "Sum",
      "chartType": "bar",
      "splitBy": "statusCategory",
      "tab": "workflows"
    },
    {
      "title": "Workflow Jobs by Event",
      "metric": "WorkflowJobCount",
      "stat": "Sum",
      "chartType": "line",
      "splitBy": "workflowEvent",
      "tab": "workflows"
    },
    {
      "title": "Workflow Job Failure Rate",
      "metric": "WorkflowJobCount",
      "stat": "Sum",
      "chartType": "line",
      "splitBy": "statusCategory",
      "color": "error",
      "tab": "workflows",
      "transform": {
        "type": "percentage",
        "numerator": ["Error"],
        "denominator": ["Success", "Error"]
      }
    },
    {
      "title": "Workflow Job Duration (P95)",
      "metric": "WorkflowJobDuration",
      "stat": "p95",
      "chartType": "line",
      "splitBy": "workflowEvent",
      "tab": "workflows"
    },
    {
      "title": "Workflow Steps by Status",
      "metric": "WorkflowStepCount",
      "stat": "Sum",
      "chartType": "bar",
      "splitBy": "statusCategory",
      "tab": "workflows"
    },
    {
      "title": "Workflow Steps by Event",
      "metric": "WorkflowStepCount",
      "stat": "Sum",
      "chartType": "line",
      "splitBy": "workflowEvent",
      "tab": "workflows"
    }
  ]
}
```

## Monitoring

The dashboard at `/admin/monitoring/dashboard` displays all configured charts organized by tab. Logs are searchable at `/admin/monitoring/logs` with filtering by source, type, user, and trace ID.

For more information on viewing metrics and logs for deployed apps, see the [Monitoring](/docs/platform-docs/deployments/monitoring) documentation. Metrics and logs are also available through the [observability API](/docs/platform-docs/deployments/monitoring/observability-api) for external monitoring integrations.
