# Loki Proxy API

## Overview

Clinic Data Service exposes Loki-compatible proxy APIs for log query paths that are still owned by data proxy:

- `/data-proxy/system-logs`: Clinic control-plane logs. The caller selects a configured system Loki datasource.
- `/data-proxy/serverless-parent-logs`: Serverless parent/control-plane logs. The caller provides `control_plane_info`; the proxy selects the configured system Loki endpoint by provider and region unless a datasource override is provided.

Business TiDB cluster logs are no longer routed through data proxy. Grafana cluster-log links should use the Clinic backend `/log/query` route via the `o11y-loki-data` datasource.

## System Logs API

System logs do not use a TiDB cluster ID and do not inject business-cluster labels such as `namespace`, `project_id`, or `cluster_id`. Upstream Loki URLs are selected only from `loki_proxy.system_endpoints`; callers cannot pass arbitrary upstream URLs.

### Endpoints

```text
GET /data-proxy/system-logs/api/v1/datasources
GET /data-proxy/system-logs/api/v1/query_range
GET /data-proxy/system-logs/api/v1/labels
GET /data-proxy/system-logs/api/v1/label/{name}/values
GET /data-proxy/system-logs/api/v1/series
```

`datasources` returns datasource names, UIDs, provider/region metadata, and the default flag. It does not expose upstream URLs.

All query/discovery endpoints require a datasource identifier:

- `datasource`
- `datasource_uid`
- `datasourceUid`
- `uid`

Proxy routing parameters are stripped before forwarding:

- `provider`
- `region`
- `datasource`
- `datasource_uid`
- `datasourceUid`
- `uid`

### Query Range Example

```bash
curl -G "${CLINIC_ENDPOINT}/data-proxy/system-logs/api/v1/query_range" \
  -H "Authorization: Bearer ${CLINIC_API_KEY}" \
  --data-urlencode 'datasource=Loki-aws-us-west-2' \
  --data-urlencode 'query={cluster_env="prod",namespace="clinic-prod-cloud"}' \
  --data-urlencode 'start=1779777500965000000' \
  --data-urlencode 'end=1779799100965000000' \
  --data-urlencode 'limit=1000'
```

### Config

```yaml
loki_proxy:
  max_limit: 1000
  default_system_datasource: "Loki-aws-us-west-2"
  system_endpoints:
    - datasource: "Loki-aws-us-west-2"
      provider: "aws"
      region: "us-west-2"
      url: "https://loki.example.com/loki/self-monitoring"
```

## Serverless Parent Logs API

Serverless parent logs route by `control_plane_info`, whose format is:

```text
projectID/vendor-region/applicationID
```

Example:

```text
us-east-1-f04/aws-us-east-1/devtier-infra
```

If `datasource`, `datasource_uid`, `datasourceUid`, or `uid` is provided, the proxy uses that configured system datasource. Otherwise it selects a configured system endpoint by provider and region parsed from `control_plane_info`.

Before forwarding, the proxy injects or replaces the Loki `cluster` matcher with:

```text
{serverlessParentEnv}-{projectID}
```

For example, in prod:

```logql
{} != `operator_controller.go`
→ {cluster="prod-us-east-1-f04"} != `operator_controller.go`
```

### Endpoints

```text
GET /data-proxy/serverless-parent-logs/api/v1/query_range
GET /data-proxy/serverless-parent-logs/api/v1/labels
GET /data-proxy/serverless-parent-logs/api/v1/label/{name}/values
GET /data-proxy/serverless-parent-logs/api/v1/series
```

All endpoints require `control_plane_info`.

### Query Range Example

```bash
curl -G "${CLINIC_ENDPOINT}/data-proxy/serverless-parent-logs/api/v1/query_range" \
  -H "Authorization: Bearer ${CLINIC_API_KEY}" \
  --data-urlencode 'control_plane_info=us-east-1-f04/aws-us-east-1/devtier-infra' \
  --data-urlencode 'query={} != `operator_controller.go`' \
  --data-urlencode 'start=1773042300000000000' \
  --data-urlencode 'end=1773049500000000000' \
  --data-urlencode 'limit=1000'
```

For `labels`, `label/{name}/values`, and `series`, the proxy injects the same `cluster` matcher into each `match[]`. If no `match[]` is provided, it creates one.

## Error Handling

Errors are returned as JSON:

```json
{
  "error": "datasource is required"
}
```

Common status codes:

- `400`: missing or invalid routing input, such as datasource or `control_plane_info`
- `500`: upstream request or response forwarding failure

## Security

- Upstream Loki URLs must come from server-side config.
- Proxy routing parameters are removed before upstream forwarding.
- System logs and serverless parent logs do not accept a business cluster ID.
