Output
Reading through logs can be noisy and challenging—Airplane allows tasks to produce explicit output separate from logs.
Airplane output is displayed in rich, user-friendly tables:

Output data model
Airplane output from a task is similar to the return value of a function. Airplane output can be any JSON value such as primitive values (strings, numbers), lists, or even complex objects.
Different Airplane tasks will return different kinds of output. For example, a SQL task will return its SELECT results as a list of objects (which is rendered as a table of values). Node.js tasks can output values however the author desires.
Output rendering in the UI
Airplane's UI does a best effort rendering of output, depending on the output data structure. The output is typically formatted into a table or multiple tables. If the output data structure is an object containing only lists as values, the UI will render each separate list as its own table, with the table name set to the key of the list. Otherwise, the entire output will be rendered as one table.
Primitive values (strings, numbers, booleans) are rendered as a single cell in a table.
Lists of primitive values are rendered as a single column table with multiple rows.
Lists of objects are rendered as a table, one row per item, and one column per key. For example,
[{"id": 1, "name": "John"}, {"id": 2, "name": "Sally"}]
will render as two rows with two columns,
"id" and "name".
Nested objects are rendered as collapsed values inside the table.

Producing output from tasks
In most task types (Node.js, Python), you can produce a basic output from a task by returning a value from the main function.
javascriptCopied1export default async function (params) {2return { id: 123, name: "abc" };3}
pythonCopied1def main(params):2return {"id": 123, "name": "abc"}
An output is typically any value that can be encoded as JSON.
For task types that are not based on a main function, Airplane captures task output by filtering stdout lines that start with certain keywords. This protocol is described in the Advanced section below.
SDK output methods
If more complicated output structures are needed, the Airplane SDK provides functions for modifying the output incrementally over the course of the task.
Set output
You can set the entire output object by calling the appropriate SDK function:
javascriptCopied1import airplane from "airplane";23export default async function (params) {4airplane.setOutput("ABC");5airplane.setOutput("DEF");6// The final output value will be "DEF".7}
pythonCopied1import airplane23def main(params):4airplane.set_output("ABC")5airplane.set_output("DEF")6# The final output value will be "DEF".
Note that returning a value from a main function is equivalent to calling the corresponding set output function at the end of task execution.
Append to output
If your output is intended to be an array, instead of setting the entire output to be an array, you can use the following:
javascriptCopied1import airplane from "airplane";23export default async function (params) {4airplane.appendOutput({ id: 1, name: "abc" });5airplane.appendOutput({ id: 2, name: "def" });6}
pythonCopied1import airplane23def main(params):4airplane.append_output({"id": 1, "name": "abc"})5airplane.append_output({"id": 2, "name": "def"})
The resulting output will be [{id: 1, name: "abc"}, {id: 2, name: "def"}]
.
During visualization, if a task produces a list of objects, the values are collected into a table with a column per key:
javascriptCopied1airplane.appendOutput({ name: "Alabama", capital: "Montgomery" });2airplane.appendOutput({ name: "Alaska", capital: "Juneau" });3airplane.appendOutput({ name: "Arizona", capital: "Phoenix" });
pythonCopied1airplane.append_output({"name": "Alabama", "capital": "Montgomery"})2airplane.append_output({"name": "Alaska", "capital": "Juneau"})3airplane.append_output({"name": "Arizona", "capital": "Phoenix"})

Common use cases
Displaying user messages
By default, users see if a run has succeeded or failed. You can output messages as you make progress (output is shown as soon as it is received), and you can also output more detailed error messages if something fails.
Exporting data
You can use Airplane output for lightweight reporting. For example, you can query a database for a set of data, output each row as a JSON object, and allow users a quick way to see data (and download it as a CSV).
Advanced
Log output protocol
Under the hood, Airplane captures task output by filtering stdout lines that start with either
airplane_output_set
or airplane_output_append
. In other words, returning from a main function,
or calling any of the SDK output functions, generates an airplane_output_set
or
airplane_output_append
line in stdout, which will be parsed by Airplane to obtain the final
task output.
Examples of such log lines are provided below:
Copied1airplane_output_set {"id": 1, "name": "abc"}
Copied1airplane_output_append {"id": 1, "name": "abc"}2airplane_output_append {"id": 2, "name": "def"}
For languages that do not have a SDK provided (e.g. Docker image, shell), printing such log lines to stdout is the recommended method for generating output from a task.
JSON paths
Setting and appending can also apply to a subset of the output instead of overwriting the entire output or appending to the main array. The airplane output set and airplane output append commands have an optional path parameter, which allows part of an existing output to be edited.
Copied1airplane_output_set {"k1": "v1", "k2": {"nested": "abc"}, "k3": [1, 2, 3]}2airplane_output_set:k1 "new value"34# Output is now: {"k1": "new value", "k2": {"nested": "abc"}, "k3": [1, 2, 3]}56# Note that these are all valid path syntaxes.7airplane_output_set:k2.nested "def"8airplane_output_set:k2["nested"] "def"9airplane_output_set:["k2"]["nested"] "def"10airplane_output_set:["k2"].nested "def"1112# Output is now: {"k1": "new value", "k2": {"nested": "def"}, "k3": [1, 2, 3]}1314airplane_output_set:k3[2] 41516# Output is now: {"k1": "new value", "k2": {"nested": "def"}, "k3": [1, 2, 4]}1718# Append also accepts paths.19airplane_output_append:k3 82021# Output is now: {"k1": "new value", "k2": {"nested": "def"}, "k3": [1, 2, 4, 8]}2223# If a set or append command encounters a null or undefined value along the24# path to the final output location, it automatically generates an empty object25# in the output, for convenience.26airplane_output_set:k4.new 52728# Output is now: {"k1": "new value", "k2": {"nested": "def"}, "k3": [1, 2, 4, 8], "k4": {"new": 5}}
The set/append output functions in the SDKs will help to automatically construct the JSON path for you, from an array of path components. Refer to the documentation of each individual SDK for the correct format.
Handling large output
Due to limitations of Docker/Kubernetes, output lines in stdout that are too long (greater than approximately 16000 characters) may not be parsed correctly, so we provide a "chunking" mechanism to split up such lines.
If you are using a SDK, this chunking is automatically handled for you.
Copied1airplane_chunk:key1 airplane_outp2airplane_chunk:key1 ut_set "Hello World!"3airplane_chunk_end:key145airplane_chunk:key2 airplane_outp6airplane_chunk:key2 ut_set "How ar7airplane_chunk:key2 e you?"8airplane_chunk_end:key2910(is equivalent to)1112airplane_output_set "Hello World!"13airplane_output_set "How are you?"