> For the complete documentation index, see [llms.txt](https://docs.dbnl.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.dbnl.com/v0.26.x/configuration/data-connections/sdk-log-ingestion.md).

# SDK Log Ingestion

Push data manually or as part of a daily orchestration job using our [Python SDK](/v0.26.x/reference/python-sdk.md). This ingestion method allows for the most flexibility, but requires the most off-platform coding.

{% hint style="info" %}
See the [Python SDK docs](/v0.26.x/reference/python-sdk.md) for more detailed information about SDK installation and functions.
{% endhint %}

The following fields are required regardless of which ingestion method you are using:

* `input`: The text input to the LLM as a `string`.
* `output`: The text response from the LLM as a `string`.
* `timestamp`: The UTC timecode associated with the LLM call as a `timestamptz`.

{% hint style="info" %}
See the [DBNL Semantic Convention](/v0.26.x/configuration/dbnl-semantic-convention.md) for other semantically recognized fields. Using these naming conventions will allow DBNL to map semantic meaning to those columns and provide better [Insights](/v0.26.x/workflow/insights.md).
{% endhint %}

## Example Code

{% hint style="info" %}
Your `DBNL_API_URL` is set during [Deployment](/v0.26.x/platform/deployment.md). See [API Authentication docs](/v0.26.x/platform/authentication.md#api-authentication) for finding your `DBNL_API_TOKEN`.
{% endhint %}

```python
DBNL_API_URL = "http://localhost:8080/api"
DBNL_API_TOKEN = ""

import random
from datetime import UTC, datetime, timedelta

import dbnl
import pandas as pd

# Login to dbnl.
dbnl.login(api_url=DBNL_API_URL, api_token=DBNL_API_TOKEN)
# Use current time as reference point.
now = datetime.now(tz=UTC)
# Get or create a new project.
project = dbnl.get_or_create_project(
    name=f"quickstart-{now.isoformat()}",
    schedule="daily",
)

# Backfill first 8 days of data.
now_date = now.replace(hour=0, minute=0, second=0, microsecond=0)
start_date = now_date - timedelta(days=8)
end_date = now_date - timedelta(days=1)
for dt in pd.date_range(start_date, end_date):
    dbnl.report_run_with_results(
        project=project,
        data_start_time=dt,
        data_end_time=dt + timedelta(days=1),
        column_data=pd.DataFrame([
            {
                "timestamp": dt + timedelta(minutes=30 * i),
                "input": f"Is {i} an even or odd number?",
                "output": random.choice(["even", "odd"]),
            }
            for i in range(20)
        ]).astype({
            "timestamp": "datetime64[us, UTC]",
            "input": "string",
            "output": "category",
        }),
    )
```
