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

# Query Usage Log

> Query per-query usage records as a Super-Admin-only Liberator dataset

# Query usage log

In Liberator **2.4** and later, Super Admins can query **`usage_log`** — a standard Liberator dataset of **one row per query per dataset**. Use it to see who queried which dataset, which `as_of` / `back_to` window they requested, how many rows came back, and whether the query succeeded or was rejected.

This is the per-query drill-down that monthly usage totals and [AI-based reporting](/administration/ai-based-reporting) do not provide. It uses the same `liberator.query` API as any other dataset, including Python, REST, Excel, and MCP.

<Note>
  `usage_log` is **Super Admin only**. It is private and hidden from the standard user catalog. Regular users cannot discover or query it, and it is not granted through ordinary Data Permissions.
</Note>

## Who can query it

| Role                 | Can query `usage_log` |
| -------------------- | --------------------- |
| **Super Admin**      | Yes                   |
| **Admin** / **User** | No                    |

If a Super Admin query returns "not entitled" or the dataset is missing, usage logging may not be enabled on that instance. Contact CloudQuant.

## Query the log

The **query parameters** `as_of` and `back_to` select **when the usage occurred** (when someone ran a query). They are not the date range those users requested — those values are columns on each row.

The **symbol / key** is the **dataset that was queried**, not a ticker. `symbols='daily_bars'` returns usage rows for queries against `daily_bars`.

```python theme={null}
import liberator

# Every query on 2026-08-28 (daily granularity)
df = liberator.get_dataframe(liberator.query(
    name='usage_log',
    back_to='2026-08-28',
    as_of='2026-08-29',
))

# Only queries against one dataset
df = liberator.get_dataframe(liberator.query(
    name='usage_log',
    symbols='daily_bars',
    back_to='2026-08-28',
    as_of='2026-08-29',
))

# One user's queries in August
df = liberator.get_dataframe(liberator.query(
    name='usage_log',
    back_to='2026-08-01',
    as_of='2026-09-01',
    where="user_id = $$jane.doe$$",
))

# Rejections and errors
df = liberator.get_dataframe(liberator.query(
    name='usage_log',
    back_to='2026-08-28',
    as_of='2026-08-29',
    where="status != $$success$$",
))
```

Recent queries are included as they complete — you do not wait for a daily rollup.

## Record grain

One row per **(query, dataset)**. A request that names several datasets produces several rows that share the same `qid`.

Rejected queries still appear, with `rows_returned` of `0` and `status` of `not_entitled`, `limit_exceeded`, or `error`.

## Columns

| Column               | Meaning                                                                 |
| -------------------- | ----------------------------------------------------------------------- |
| `timestamp` / `muts` | When the usage record was stored (Liberator's usual time axis)          |
| `symbol`             | Key field — the dataset that was queried (same value as `dataset_name`) |
| `dataset_name`       | Dataset the user requested                                              |
| `user_id`            | Liberator username that ran the query                                   |
| `system`             | Client / system identifier from the request (for example `API`)         |
| `as_of`              | `as_of` the caller passed (the original query's end time)               |
| `back_to`            | `back_to` the caller passed (the original query's start time)           |
| `rows_returned`      | Rows delivered for that dataset; `0` if the query was rejected          |
| `status`             | Outcome — see below                                                     |
| `qid`                | Query id; shared by every dataset row from the same request             |
| `request_id`         | Optional correlation id from the connection                             |
| `detail`             | Extra reason text (for example an error class, or a client disconnect)  |
| `query_timestamp`    | UTC microseconds when the original query finished                       |

Do not confuse the **columns** `as_of` / `back_to` (what the user asked for) with the **parameters** `as_of` / `back_to` on your `usage_log` query (which slice of the log you want).

### Status values

| `status`         | Meaning                                                                         |
| ---------------- | ------------------------------------------------------------------------------- |
| `success`        | Query completed and returned data (including an empty result that was allowed)  |
| `limit_exceeded` | Rejected by a usage or entitlement cap (for example max rows or max query days) |
| `not_entitled`   | Caller is not entitled to the dataset                                           |
| `error`          | Any other failure                                                               |

## Retention

Records are kept for **at least 30 days**. Retention is configured for the instance — contact CloudQuant to change it.

## Related

<CardGroup cols={2}>
  <Card title="AI-based reporting" icon="chart-mixed" href="/administration/ai-based-reporting">
    Aggregated usage, user, and entitlement reports in the Admin UI
  </Card>

  <Card title="System monitoring" icon="heart-pulse" href="/system-monitoring/overview">
    Cluster health, long queries, and license utilization
  </Card>

  <Card title="Fine-grained permissions" icon="sliders" href="/administration/fine-grained-permissions">
    Caps that show up as `limit_exceeded` on usage\_log
  </Card>

  <Card title="What's new in 2.4" icon="rocket" href="/whats-new/liberator-2.4">
    Liberator 2.4 release notes
  </Card>
</CardGroup>
