---
myst:
html_meta:
description: "Upload journal-style JSON Lines log files to a dataset's log channel."
---
# Journal JSON logs
{.lead}
Upload journald exports and other JSON Lines log files with {py:meth}`~nominal.core.Dataset.add_journal_json`.
Each line becomes one entry in a log channel.
To send logs from a running program instead, see [Stream logs](/guides/streaming/logs.md).
```{include} /guides/_snippets/connect-the-client.md
```
## Upload a file
The file needs a `.jsonl` or `.jsonl.gz` name and one JSON object per line:
```json
{"__REALTIME_TIMESTAMP": "1789051099000000", "MESSAGE": "Sent ACTUATE_MOTOR command", "level": "INFO"}
{"__REALTIME_TIMESTAMP": "1789051100000000", "MESSAGE": "Motor temperature above target", "level": "WARN"}
```
- `MESSAGE` holds the log message.
- `__REALTIME_TIMESTAMP` holds microseconds since the Unix epoch.
- Every other field, here `level`, becomes a log argument with a string value.
- Lines without a message or timestamp are skipped.
```python
dataset = client.create_dataset("Engine test logs")
file = dataset.add_journal_json("engine.jsonl", channel="engine_logs") # channel defaults to "logs"
file.poll_until_ingestion_completed()
```
## Use another timestamp field
Pass both `timestamp_column` and `timestamp_type` for a different field or epoch unit:
```python
dataset.add_journal_json(
"engine-ms.jsonl",
channel="engine_logs",
timestamp_column="timestamp_ms",
timestamp_type="epoch_milliseconds",
)
```
`timestamp_type` takes epoch units only.
For ISO 8601 or relative times, convert them to epoch values first, or parse the entries and [stream them](/guides/streaming/logs.md).
## View the logs
Add the dataset to an [asset](/guides/assets.md#add-data-with-data-scopes) or a [run](/guides/runs.md).
In a workbook on that asset or run, add a **Logs** panel and select the `engine_logs` channel.