Creating a custom span
Usectx.step.trace() to create a custom span:
from polos import workflow, WorkflowContext
@workflow
async def my_workflow(ctx: WorkflowContext, input: MyInput):
# Custom span for a database query
with ctx.step.trace("database_query", {"table": "users"}) as span:
# Your code here
result = await ctx.step.run("query_database", query_database, "SELECT * FROM users")
# Add attributes to the span
span.set_attribute("row_count", len(result))
return result
import { defineWorkflow, WorkflowContext } from '@polos/sdk';
const myWorkflow = defineWorkflow<MyInput, {}, typeof result>(
{ id: 'my-workflow' },
async (ctx, input) => {
// Custom span for a database query
const span = ctx.step.trace('database_query', { table: 'users' });
try {
// Your code here
const result = await ctx.step.run('queryDatabase', () => queryDatabase('SELECT * FROM users'));
// Add attributes to the span
span.setAttribute('rowCount', result.length);
return result;
} finally {
span.end();
}
}
);
Setting attributes
You can add metadata to spans using attributes:with ctx.step.trace("external_api_call") as span:
response = await ctx.step.run("external_api", call_external_api, url)
# Set a single attribute
span.set_attribute("status_code", response.status_code)
span.set_attribute("success", response.ok)
# Set multiple attributes at once
span.set_attributes({
"url": url,
"response_size": len(response.content),
"content_type": response.headers.get("content-type"),
})
const span = ctx.step.trace('externalApiCall');
try {
const response = await ctx.step.run('externalApi', () => callExternalApi(url));
// Set a single attribute
span.setAttribute('statusCode', response.statusCode);
span.setAttribute('success', response.ok);
// Set multiple attributes at once
span.setAttributes({
url: url,
responseSize: response.content.length,
contentType: response.headers.get('content-type'),
});
} finally {
span.end();
}
Adding events
Events mark specific moments within a span:with ctx.step.trace("data_processing") as span:
span.add_event("started_validation")
await ctx.step.run("validate_data", validate_data, data)
span.add_event("validation_complete", attributes={
"records_validated": len(data),
"errors_found": 0,
})
process_data(data)
span.add_event("processing_complete")
const span = ctx.step.trace('dataProcessing');
try {
span.addEvent('startedValidation');
await ctx.step.run('validateData', () => validateData(data));
span.addEvent('validationComplete', { attributes: {
recordsValidated: data.length,
errorsFound: 0,
}});
processData(data);
span.addEvent('processingComplete');
} finally {
span.end();
}
Nested spans
Spans can be nested to show hierarchical relationships:@workflow
async def my_workflow(ctx: WorkflowContext, input: MyInput):
with ctx.step.trace("parent_operation") as parent_span:
# Do some work
await ctx.step.run("step_one", step_one_func)
# Nested span within the parent
with ctx.step.trace("child_operation") as child_span:
child_span.set_attribute("nested", True)
await ctx.step.run("do_child_work", do_child_work)
await ctx.step.run("step_two", step_two_func)
import { defineWorkflow, WorkflowContext } from '@polos/sdk';
const myWorkflow = defineWorkflow<MyInput, {}, void>(
{ id: 'my-workflow' },
async (ctx, input) => {
const parentSpan = ctx.step.trace('parentOperation');
try {
// Do some work
await ctx.step.run('stepOne', () => stepOneFunc());
// Nested span within the parent
const childSpan = ctx.step.trace('childOperation');
try {
childSpan.setAttribute('nested', true);
await ctx.step.run('doChildWork', () => doChildWork());
} finally {
childSpan.end();
}
await ctx.step.run('stepTwo', () => stepTwoFunc());
} finally {
parentSpan.end();
}
}
);
async def process_data(ctx: WorkflowContext, data: dict):
with ctx.step.trace("data_transformation", {"input_size": len(data)}) as span:
transformed = transform(data)
span.set_attributes({
"output_size": len(transformed),
"success": True,
})
span.add_event("transformation_complete")
return transformed
async function processData(ctx: WorkflowContext, data: Record<string, unknown>) {
const span = ctx.step.trace('dataTransformation', { inputSize: Object.keys(data).length });
try {
const transformed = transform(data);
span.setAttributes({
outputSize: Object.keys(transformed).length,
success: true,
});
span.addEvent('transformationComplete');
return transformed;
} finally {
span.end();
}
}