Add Logs to an Asset

To use this guide, install the Nominal Python library with pip3 install nominal.

See Quickstart for more details.

Please contact us if you’re not sure whether your organization has access to Nominal.

Log files are a standard output from Assets such as aircraft, land vehicles, manufacturing equipment, and practically any present-day machine with an on-board computer.

Nominal makes it simple to upload log files to a Nominal Asset for collaborative inspection, root-cause analysis, and automated alerting.

In Nominal, Assets are containers of multimodal test data - including Datasets, Videos, Logs, and database connections.

To see your organization’s latest Assets, head over to the Assets page

Connect to Nominal

When using the Nominal client library, there are two primary ways of authenticating:

First, run the following in your terminal and follow on-screen prompts to insert the base_url and API key:

$$ python -m nominal auth set-token
>
># Alternatively, use the globally installed CLI
>$ nom auth set-token

This will store your API key in a config file ~/.nominal.yml. The API key will automatically be used when using the client again.

1import nominal
2
3# Simply grab the "default" client using your stored credentials
4client = nominal.get_default_client()
5
6# Get details about the currently logged-in user to validate authentication
7# Will display an object like: `User(display_name='your_email@your_company.com', ...)`
8print(client.get_user())
1import nominal
2
3# Set login details for the user
4nominal.set_token("<insert api key>")
5
6# Get an instance of the client using provided credentials
7client = nominal.get_default_client()
8
9# Get details about the currently logged-in user to validate authentication
10# Will display an object like: `User(display_name='your_email@your_company.com', ...)`
11print(client.get_user())

NOTE: you should never share your Nominal API key with anyone. We therefore recommend that you not save it in your code and/or scripts.

  • If you trust the computer you are on, use nom to store the credential to disk.
  • Otherwise, use a password manager such as 1password or bitwarden to keep your token safe.
If you’re not sure whether your company has a Nominal tenant, please reach out to us.

Create an Asset

First, we’ll create an empty asset to upload our log file:

1import polars as pl
2import nominal as nm
3
4df = pl.read_csv('hf://datasets/nominal-io/frosty-flight/frosty_flight_1k_rows.csv')
5df.write_csv('frosty_flight_1k_rows.csv')
6
7dataset = nm.upload_csv(
8 'frosty_flight_1k_rows.csv',
9 name = 'Dataset for Asset: UAV Drone',
10 timestamp_column = 'source_time',
11 timestamp_type = 'iso_8601',
12)
13
14uav_drone_asset = nm.create_asset(
15 name = 'Frosty Flight'
16)
17uav_drone_asset.add_dataset(
18 dataset = dataset,
19 data_scope_name = 'dataset'
20)
21
22print(uav_drone_asset.rid)

If you navigate to your organization’s Assets page, you’ll see an Asset at the top called “‘Frosty Flight.”

Generate a log file

We’ll generate a demo log file to add to our Asset.

To make the demo log file visually interesting and distinct, we’ll add a random sparkline chart to each log file line:

1import random
2
3def generate_sparkline(length=10):
4 """Generate a random sparkline in ASCII."""
5 data = [random.randint(1, 10) for _ in range(length)]
6 chars = "▁▂▃▄▅▆▇█"
7 max_value = max(data)
8 min_value = min(data)
9
10 def normalize(value):
11 if max_value == min_value:
12 return 0
13 return int((value - min_value) / (max_value - min_value) * (len(chars) - 1))
14
15 sparkline = ''.join(chars[normalize(value)] for value in data)
16 return sparkline

Nominal log files are defined in Python as a list of tuples:

1logs = [
2 (df['source_time'][i], f"Log message {i} {generate_sparkline(random.randint(15, 40))}")
3 for i in range(len(df['source_time']))
4]
5
6for row in logs[:5]:
7 print(row)
('2024-06-08T05:58:42.000Z', 'Log message 0 ▅▅▅▂▅█▆▆▁▅▆▅▇███▆▅▄█')
('2024-06-08T05:58:51.000Z', 'Log message 1 ▆▃▃▃▅▃▄▃▅▁▁▂▁▄▄█▄▇▂▇▆▁▇█▃▁▅▆▃▁█▆')
('2024-06-08T05:58:52.000Z', 'Log message 2 ▁▂▄▃▄▄▂▄▃▆▁▇▁▄▅▄▄▄▄█▁▄▇▂▂▁')
('2024-06-08T05:58:52.000Z', 'Log message 3 ▁█▅▅▆▃▇▂█▂▇▃▄▂▇▆▁▁▄▃▄▁█▄█▂')
('2024-06-08T05:58:52.000Z', 'Log message 4 ▄██▁▄▆▃▁█▄▃▂▄▁▇▄')

Finally, add the log file to uav_drone_asset:

1import nominal as nm
2
3log_set = nm.create_log_set(
4 logs=logs,
5 name="Sparkline Logs",
6 description="description"
7)
8
9data_scope_name = "fun_with_logs"
10
11uav_drone_asset.add_log_set(data_scope_name, log_set)

If you visit the Datasets tab of the ‘Frosty Flight’ Assets page, you’ll see “Sparkline Logs” in the datasets table.

To inspect “Sparkline Logs”, open the Asset in an empty Workbook and click on the “Logs” pane at the bottom of the window.

Retrieve log files

To retrieve a log file, use the get_log_set() and stream_logs() convenience functions.

You can find the resource ID (“RID”) for log files under the “Data sources” tab of any Run that has an associated log file.

1import nominal as nm
2
3log = nm.get_log_set("ri.data-source.cerulean-staging.log-set.8bc1f396-a42e-40db-9680-e686e288e45d")
4
5counter = 1
6for line in log.stream_logs():
7 counter += 1
8 print(line)
9 if counter > 5:
10 break
Log(timestamp=1728058190751960000, body='Log message 0 ▅▅▅▂▅█▆▆▁▅▆▅▇███▆▅▄█')
Log(timestamp=1728058191751960000, body='Log message 1 ▆▃▃▃▅▃▄▃▅▁▁▂▁▄▄█▄▇▂▇▆▁▇█▃▁▅▆▃▁█▆')
Log(timestamp=1728058192751960000, body='Log message 2 ▁▂▄▃▄▄▂▄▃▆▁▇▁▄▅▄▄▄▄█▁▄▇▂▂▁')
Log(timestamp=1728058193751960000, body='Log message 3 ▁█▅▅▆▃▇▂█▂▇▃▄▂▇▆▁▁▄▃▄▁█▄█▂')
Log(timestamp=1728058194751960000, body='Log message 4 ▄██▁▄▆▃▁█▄▃▂▄▁▇▄')