# The basics of querying logs

This document provides guidance on querying logs using the groundcover API. It outlines the necessary authentication steps, request structure, and examples to help you retrieve log data effectively.

### Endpoint

**POST** `https://app.groundcover.com/api/logs/v2/query`

This endpoint allows you to execute queries to retrieve log data based on specified criteria.

### Authentication

To authenticate your requests, include your API key in the Authorization header:

* **Authorization**: `Bearer <YOUR_API_KEY>`

**Example:**

```bash
curl 'https://app.groundcover.com/api/logs/v2/query' \
  -H 'accept: application/json' \
  -H 'authorization: Bearer <YOUR_API_KEY>' \
  -H 'Content-Type: application/json' \
  --data-raw '{"start":"2025-12-24T07:54:29.459Z","end":"2025-12-24T13:54:29.459Z","group":null,"limit":200,"skip":0,"sortBy":"timestamp","sortOrder":"desc","selectors":[],"optimizeSearch":true}'
```

### Request Body

The request body should be a JSON object containing the following parameters:

| Parameter        | Type           | Description                                                                                                                     | Example                      |
| ---------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| `start`          | string         | Start time for the query in ISO 8601 format                                                                                     | `"2025-12-24T07:54:29.459Z"` |
| `end`            | string         | End time for the query in ISO 8601 format                                                                                       | `"2025-12-24T13:54:29.459Z"` |
| `group`          | object \| null | Filtering/grouping conditions; set to `null` if not filtering                                                                   | See examples below           |
| `limit`          | integer        | Maximum number of log entries to return - The maximum allowed value is: 5000                                                    | `200`                        |
| `skip`           | integer        | Number of log entries to skip from the start                                                                                    | `0`                          |
| `sortBy`         | string         | Field to sort by                                                                                                                | `"timestamp"`                |
| `sortOrder`      | string         | Sort order; either `"asc"` for ascending or `"desc"` for descending                                                             | `"desc"`                     |
| `selectors`      | array          | List of additional fields/attributes to return with logs; empty array returns default fields. Format: `[{"key": "field.name"}]` | `[]`                         |
| `optimizeSearch` | boolean        | Whether to optimize the search query (should always be `true`)                                                                  | `true`                       |

{% hint style="warning" %}
Note: The `limit` parameter can get a maximum value of 5000
{% endhint %}

**Example Request Body:**

```json
{
  "start": "2025-12-24T07:54:29.459Z",
  "end": "2025-12-24T13:54:29.459Z",
  "group": null,
  "limit": 200,
  "skip": 0,
  "sortBy": "timestamp",
  "sortOrder": "desc",
  "selectors": [],
  "optimizeSearch": true
}
```

### Example Queries

#### Query Error Logs from Last 6 Hours

To retrieve logs with the level "error" from the last 6 hours, use the `group` parameter with filtering conditions:

```bash
curl 'https://app.groundcover.com/api/logs/v2/query' \
  -H 'accept: application/json' \
  -H 'authorization: Bearer <YOUR_API_KEY>' \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "start": "2025-12-24T12:06:54.169Z",
    "end": "2025-12-24T18:06:54.169Z",
    "group": {
      "operator": "and",
      "conditions": [{
        "filters": [{
          "op": "match",
          "value": "error"
        }],
        "key": "level",
        "origin": "root",
        "type": "string"
      }]
    },
    "limit": 200,
    "skip": 0,
    "sortBy": "timestamp",
    "sortOrder": "desc",
    "selectors": [],
    "optimizeSearch": true
  }'
```

**Note:** Ensure that the `start` and `end` times are adjusted to reflect the desired time range. The `group` parameter structure filters logs where the `level` field matches "error".

#### Group Parameter Structure

The `group` parameter uses the following structure for filtering:

```json
{
  "operator": "and",
  "conditions": [{
    "filters": [{
      "op": "match",
      "value": "error"
    }],
    "key": "level",
    "origin": "root",
    "type": "string"
  }]
}
```

* `conditions`: Array of filter conditions
  * `filters`: Array of filter operations
    * `op`: Operation type (e.g., `"match"`)
    * `value`: Value to match
  * `key`: Field name to filter on (e.g., `"level"`)
  * `origin`: Origin of the field (typically `"root"`)
  * `type`: Data type of the field (e.g., `"string"`)
* `operator`: Logical operator to combine conditions (e.g., `"and"`, `"or"`)

To query all logs without filtering, set `group` to `null`.

### Response

The response is a JSON object containing log entries and metadata. Each log entry includes details such as timestamp, log level, line content, workload information, and associated metadata.

**Example Response:**

```json
{
  "logs": [
    {
      "timestamp": "2025-12-24T13:54:29.458482612Z",
      "guid": "17666060341330778405",
      "line": "Loading installed providers to workflow",
      "level": "info",
      "format": "json",
      "workload": "groundcover-incloud-keep-backend",
      "pod_name": "groundcover-incloud-keep-backend-546f4c89f9-bmgt5",
      "namespace": "groundcover-incloud",
      "container": "keep",
      "podUid": "9e919ced-2f7c-442a-a31f-5f80790d735d",
      "envType": "K8s",
      "node": "ip-10-1-7-219.eu-west-3.compute.internal",
      "host": "ip-10-1-7-219.eu-west-3.compute.internal",
      "instance": "groundcover-incloud-keep-backend-546f4c89f9-bmgt5",
      "instanceId": "9e919ced-2f7c-442a-a31f-5f80790d735d",
      "instanceUid": "460424509714310639",
      "service": "groundcover-incloud-keep-backend",
      "functionName": "",
      "lambdaArn": "",
      "cluster": "groundcover-experiments",
      "env": "prod",
      "source": "k8s",
      "traceId": "cbbc0f1b72c3b9db69f3858edea9d970",
      "spanId": "fb2f0af20aa42300",
      "additionalColumns": {},
      "metadata": {}
    },
    {
      "timestamp": "2025-12-24T13:54:29.456626838Z",
      "guid": "17368171834420881877",
      "line": "Error getting workflow",
      "level": "error",
      "format": "json",
      "workload": "gc-keep-backend",
      "pod_name": "gc-keep-backend-6c9b99b67f-rhwm8",
      "namespace": "groundcover-main",
      "container": "keep",
      "podUid": "098e59f5-be01-4a4e-84b9-4c616961848a",
      "envType": "K8s",
      "node": "ip-172-31-47-39.eu-west-3.compute.internal",
      "host": "ip-172-31-47-39.eu-west-3.compute.internal",
      "instance": "gc-keep-backend-6c9b99b67f-rhwm8",
      "instanceId": "098e59f5-be01-4a4e-84b9-4c616961848a",
      "instanceUid": "7534023078789880662",
      "service": "gc-keep-backend",
      "functionName": "",
      "lambdaArn": "",
      "cluster": "noam-test",
      "env": "",
      "source": "k8s",
      "traceId": "69620eeecb241c1e56b077b7240f522e",
      "spanId": "53f160665fa2d452",
      "additionalColumns": {},
      "metadata": {}
    }
  ],
  "levels": ["info", "error"],
  "raiseAlert": true,
  "limitReached": false,
  "done": true,
  "optimizedKeys": null
}
```

### Using Selectors

The `selectors` parameter allows you to specify additional fields and attributes to return with the logs. By default, logs include standard fields like `timestamp`, `level`, `line`, `workload`, `namespace`, `cluster`, etc. Use `selectors` to request additional fields.

**Example: Query with selectors to get additional fields**

```bash
curl 'https://app.groundcover.com/api/logs/v2/query' \
  -H 'accept: application/json' \
  -H 'authorization: Bearer <YOUR_API_KEY>' \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "start": "2025-12-24T14:10:06.183Z",
    "end": "2025-12-24T20:10:06.183Z",
    "group": {
      "conditions": [{
        "filters": [{"op": "phrase_search", "value": "POST /ingest"}],
        "origin": "root",
        "type": "freetext"
      }],
      "operator": "and"
    },
    "limit": 200,
    "skip": 0,
    "sortBy": "timestamp",
    "sortOrder": "desc",
    "selectors": [{"key": "request.method"}, {"key": "cluster"}, {"key": "host.id"}],
    "optimizeSearch": true
  }'
```

### Filtering with Group Parameter

The `group` parameter allows you to filter logs based on field values. Here are some examples:

**Single condition (level = error):**

```json
{
  "group": {
    "operator": "and",
    "conditions": [{
      "filters": [{"op": "match", "value": "error"}],
      "key": "level",
      "origin": "root",
      "type": "string"
    }]
  }
}
```

**Multiple conditions (using AND operator):**

```json
{
  "group": {
    "operator": "and",
    "conditions": [
      {
        "filters": [{"op": "match", "value": "error"}],
        "key": "level",
        "origin": "root",
        "type": "string"
      },
      {
        "filters": [{"op": "match", "value": "prod"}],
        "key": "env",
        "origin": "root",
        "type": "string"
      }
    ]
  }
}
```

**No filtering (query all logs):**

```json
{
  "group": null
}
```

### Best Practices

1. **Time Range**: Always specify appropriate `start` and `end` times to limit the scope of your query and improve performance.
2. **Result Limits**: Use the `limit` parameter to control the number of results returned. For large datasets, consider using pagination (see the [Pagination documentation](https://docs.groundcover.com/use-groundcover/remote-access-and-apis/api-examples/query-logs/pagination)).
3. **Optimization**: Always set `optimizeSearch` to `true` for better query performance on large datasets.
4. **Filtering**: Use the `group` parameter with conditions to filter logs by field values. Set `group` to `null` to query all logs without filtering.
5. **Selectors**: Use the `selectors` array to specify additional fields you want returned with the logs. Leave it empty to get default fields.

###
