Spores Logging API Reference¶
Core Module¶
mycorrhizal.spores ¶
Spores - Event and Object Logging for Observability
OCEL (Object-Centric Event Log) compatible logging system for tracking events and objects in Mycorrhizal systems. Provides automatic extraction of events and objects from DSL execution.
Usage (Standalone Event and Object Logging): from mycorrhizal.spores import configure, get_spore_sync, get_spore_async from mycorrhizal.spores.transport import SyncFileTransport, AsyncFileTransport from mycorrhizal.spores.models import SporesAttr from pydantic import BaseModel from typing import Annotated
# Mark domain model fields for object attribute logging
class Order(BaseModel):
id: str
status: Annotated[str, SporesAttr]
total: Annotated[float, SporesAttr]
# Sync code
configure(transport=SyncFileTransport("logs/ocel.jsonl"))
spore = get_spore_sync(__name__)
@spore.log_event(
event_type="OrderCreated",
relationships={"order": ("return", "Order")},
)
def create_order(customer: Customer, items: list) -> Order:
return Order(...)
# Async code
configure(transport=AsyncFileTransport("logs/ocel.jsonl"))
aspore = get_spore_async(__name__)
@aspore.log_event(
event_type="OrderCreated",
relationships={"order": ("return", "Order")},
)
async def create_order_async(customer: Customer, items: list) -> Order:
return Order(...)
Usage (DSL Adapters): from mycorrhizal.spores import configure, spore from mycorrhizal.spores.models import EventAttr, ObjectRef, ObjectScope from pydantic import BaseModel from typing import Annotated
# Mark blackboard fields for event attribute extraction
class MissionContext(BaseModel):
mission_id: Annotated[str, EventAttr]
robot: Annotated[Robot, ObjectRef(qualifier="actor", scope=ObjectScope.GLOBAL)]
# Mark object types for logging
@spore.object(object_type="Robot")
class Robot(BaseModel):
id: str
name: str
DSL Adapters
HyphaAdapter - Log Petri net transitions with token relationships RhizomorphAdapter - Log behavior tree node execution with status SeptumAdapter - Log state machine execution and lifecycle events
Annotation Types
EventAttr - Mark blackboard fields for automatic event attribute extraction (DSL adapters) SporesAttr - Mark domain model fields for automatic object attribute logging (log_event) ObjectRef - Mark blackboard fields as object references with scope
Key Concepts
Event - Something that happens at a point in time with attributes Object - An entity with a type and attributes Relationship - Link between events and objects (e.g., "actor", "target")
Object Scopes
EVENT - Object exists only for this event (default) GLOBAL - Object exists across all events (deduplicated by ID)
SporesConfig
dataclass
¶
SporesConfig(enabled: bool = True, object_cache_size: int = 128, encoder: Optional[Encoder] = None, transport: Optional[Transport] = None, eviction_policy: EvictionPolicy = EVICT_AND_LOG, touch_resend_n: int = 100)
Global configuration for the Spores logging system.
Attributes:
| Name | Type | Description |
|---|---|---|
enabled |
bool
|
Whether spores logging is enabled |
object_cache_size |
int
|
Maximum objects in LRU cache |
encoder |
Optional[Encoder]
|
Encoder instance to use |
transport |
Optional[Transport]
|
Transport instance to use (required for logging to work) |
eviction_policy |
EvictionPolicy
|
Policy for handling cache eviction |
touch_resend_n |
int
|
Resend object every N touches (0 to disable periodic resend) |
EvictionPolicy ¶
Bases: str, Enum
Cache eviction policy for object logging.
Attributes:
| Name | Type | Description |
|---|---|---|
EVICT_AND_LOG |
Evict from cache when full, log immediately via sync/async path |
|
EVICT_AND_BUFFER |
Evict from cache, buffer for later logging (future) |
|
NO_EVICT |
Keep in cache until explicit flush (future) |
CacheMetrics
dataclass
¶
Track cache eviction statistics.
EventLogger ¶
Bases: ABC
Abstract base class for event loggers.
Implementations can be sync or async, but the interface is the same.
event
abstractmethod
¶
AsyncEventLogger ¶
Bases: EventLogger
Async event logger for use in async contexts.
Source code in src/mycorrhizal/spores/core.py
event
async
¶
event(event_type: str, relationships: Dict[str, Relationship] | None = None, **kwargs) -> None
Log an event asynchronously.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
The type of event |
required |
relationships
|
Dict[str, Relationship] | None
|
Optional dict of qualifier -> Relationship for OCEL object relationships |
None
|
**kwargs
|
Event attributes |
{}
|
Source code in src/mycorrhizal/spores/core.py
log_object
async
¶
Log an object asynchronously.
Source code in src/mycorrhizal/spores/core.py
log_event ¶
log_event(event_type: str, relationships: Dict[str, tuple] | None = None, attributes: Dict[str, Any] | None = None)
Decorator factory that logs events with auto-logged object relationships (async version).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
The type of event to log |
required |
relationships
|
Dict[str, tuple] | None
|
Dict mapping qualifiers to relationship specs: - qualifier: Relationship qualifier (e.g., "order", "customer") - spec: 2-tuple (source, obj_type) or 3-tuple (source, obj_type, attrs) - source: Where to get object ("return", "ret", param name, "self") - obj_type: OCEL object type - attrs: Optional list of attribute names to log (omitted = auto-detect SporesAttr) |
None
|
attributes
|
Dict[str, Any] | None
|
Dict mapping event attribute names to values or callables |
None
|
Returns:
| Type | Description |
|---|---|
|
Decorator function |
Source code in src/mycorrhizal/spores/core.py
_build_context ¶
Build context dict for async version.
Source code in src/mycorrhizal/spores/core.py
_resolve_source ¶
Resolve source for async version.
If source is "bb" (blackboard) and obj_type is provided, extract the field of that type from the blackboard instead of returning the entire blackboard.
Source code in src/mycorrhizal/spores/core.py
_find_object_by_type ¶
Find a field in the blackboard that matches the requested object type.
Scans the blackboard's fields and returns the first field whose type annotation matches obj_type.
Source code in src/mycorrhizal/spores/core.py
_get_object_id ¶
Extract object ID for async version.
_extract_object_attrs ¶
Extract attributes for async version.
Source code in src/mycorrhizal/spores/core.py
_extract_spores_attrs ¶
Extract SporesAttr-marked fields for async version.
Source code in src/mycorrhizal/spores/core.py
_evaluate_expression ¶
Evaluate expression for async version.
Source code in src/mycorrhizal/spores/core.py
SyncEventLogger ¶
Bases: EventLogger
Sync event logger for use in synchronous contexts.
Uses daemon threads for fire-and-forget logging - business logic never blocks. Logs are written via sync transport's blocking send() (no event loop needed).
Source code in src/mycorrhizal/spores/core.py
event ¶
event(event_type: str, relationships: Dict[str, Relationship] | None = None, **kwargs) -> None
Log an event in background daemon thread (fire-and-forget).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
The type of event |
required |
relationships
|
Dict[str, Relationship] | None
|
Optional dict of qualifier -> Relationship for OCEL object relationships |
None
|
**kwargs
|
Event attributes |
{}
|
Source code in src/mycorrhizal/spores/core.py
log_object ¶
Log an object in background daemon thread (fire-and-forget).
Source code in src/mycorrhizal/spores/core.py
log_event ¶
log_event(event_type: str, relationships: Dict[str, tuple] | None = None, attributes: Dict[str, Any] | None = None)
Decorator factory that logs events with auto-logged object relationships.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
The type of event to log |
required |
relationships
|
Dict[str, tuple] | None
|
Dict mapping qualifiers to relationship specs: - qualifier: Relationship qualifier (e.g., "order", "customer") - spec: 2-tuple (source, obj_type) or 3-tuple (source, obj_type, attrs) - source: Where to get object ("return", "ret", param name, "self") - obj_type: OCEL object type - attrs: Optional list of attribute names to log (omitted = auto-detect SporesAttr) |
None
|
attributes
|
Dict[str, Any] | None
|
Dict mapping event attribute names to values or callables |
None
|
Returns:
| Type | Description |
|---|---|
|
Decorator function |
Example
@spore.log_event(
event_type="OrderCreated",
relationships={
"order": ("return", "Order"), # 2-tuple: auto-detect SporesAttr
"customer": ("customer", "Customer"), # 2-tuple: auto-detect SporesAttr
},
attributes={
"item_count": lambda items: len(items),
},
)
def create_order(customer: Customer, items: list) -> Order:
order = Order(...)
return order
Source code in src/mycorrhizal/spores/core.py
774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 | |
_build_context ¶
Build a context dict for resolving sources and evaluating expressions.
Returns dict with
- 'return' and 'ret': The return value
- 'self': For methods, the self parameter
- All function parameters by name
Source code in src/mycorrhizal/spores/core.py
_resolve_source ¶
Resolve an object from a source expression.
Sources
- "return" or "ret": Return value
- "self": For methods
- Any other string: Parameter name from context
- If source is "bb" (blackboard) and obj_type is provided, extract the field of that type
Source code in src/mycorrhizal/spores/core.py
_find_object_by_type ¶
Find a field in the blackboard that matches the requested object type.
Scans the blackboard's fields and returns the first field whose type annotation matches obj_type.
Source code in src/mycorrhizal/spores/core.py
_get_object_id ¶
Extract object ID from an object.
Tries
- obj.id attribute
- str(obj)
Source code in src/mycorrhizal/spores/core.py
_extract_object_attrs ¶
Extract attributes from an object for logging.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
obj
|
Any
|
The object to extract from |
required |
attrs_spec
|
list | dict
|
Either a list of attribute names, or a dict of {name: expression} |
required |
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
Dict of attribute name -> value |
Source code in src/mycorrhizal/spores/core.py
_extract_spores_attrs ¶
Extract attributes marked with SporesAttr from a Pydantic model.
Checks the object's class annotations for Annotated[type, SporesAttr] fields.
Source code in src/mycorrhizal/spores/core.py
_evaluate_expression ¶
Evaluate an expression for event or object attributes.
Supports
- Static values (strings, numbers, etc.)
- Callables (called with context)
- Strings that are parameter references or attribute accesses
Source code in src/mycorrhizal/spores/core.py
Event
dataclass
¶
Event(id: str, type: str, activity: Optional[str] = None, time: datetime = now(), attributes: Dict[str, EventAttributeValue] = dict(), relationships: Dict[str, Relationship] = dict())
An OCEL event representing something that happened.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
Unique event identifier |
type |
str
|
Event type/category (event class) |
activity |
Optional[str]
|
Optional semantic activity label (defaults to type if null) |
time |
datetime
|
When the event occurred |
attributes |
Dict[str, EventAttributeValue]
|
Event attributes (name -> EventAttributeValue) |
relationships |
Dict[str, Relationship]
|
Objects related to this event (qualifier -> Relationship) |
Object
dataclass
¶
Object(id: str, type: str, attributes: Dict[str, ObjectAttributeValue] = dict(), relationships: Dict[str, Relationship] = dict())
An OCEL object representing an entity in the system.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
Unique object identifier |
type |
str
|
Object type/category |
attributes |
Dict[str, ObjectAttributeValue]
|
Object attributes (name -> ObjectAttributeValue) |
relationships |
Dict[str, Relationship]
|
Other objects related to this object (qualifier -> Relationship) |
LogRecord
dataclass
¶
A log record containing either an event or an object (not both).
This is the union type used for streaming to OCEL consumers.
Attributes:
| Name | Type | Description |
|---|---|---|
event |
Optional[Event]
|
An event record (if logging an event) |
object |
Optional[Object]
|
An object record (if logging an object) |
Note
Exactly one of event or object must be set.
__post_init__ ¶
Validate that exactly one of event or object is set.
Source code in src/mycorrhizal/spores/models.py
Relationship
dataclass
¶
A relationship from an event to an object.
Attributes:
| Name | Type | Description |
|---|---|---|
object_id |
str
|
The ID of the related object |
qualifier |
str
|
How the object relates to the event (e.g., "input", "output", "actor") |
EventAttributeValue
dataclass
¶
An attribute value for an event.
Event attributes don't have timestamps because the event time itself is sufficient.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The attribute name |
value |
str
|
The string representation of the value |
type |
str
|
The data type ("string", "integer", "float", "boolean", "timestamp") |
ObjectAttributeValue
dataclass
¶
An attribute value for an object.
OCEL attributes include timestamps for versioning.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The attribute name |
value |
str
|
The string representation of the value |
type |
str
|
The data type ("string", "integer", "float", "boolean", "timestamp") |
time |
Optional[datetime]
|
When this attribute value was set |
ObjectRef
dataclass
¶
ObjectRef(qualifier: str, scope: Union[ObjectScope, str] = EVENT)
Metadata annotation for object references in blackboard interfaces.
Used with typing.Annotated to mark fields as OCEL objects:
robot: Annotated[Robot, ObjectRef(qualifier="actor", scope=ObjectScope.GLOBAL)]
Attributes:
| Name | Type | Description |
|---|---|---|
qualifier |
str
|
How the object relates to events ("input", "output", "actor", etc.) |
scope |
Union[ObjectScope, str]
|
When to include this object in events |
__post_init__ ¶
ObjectScope ¶
Bases: Enum
Scope for object associations with events.
EventAttr
dataclass
¶
Metadata annotation for event attributes in blackboard interfaces.
Used with typing.Annotated to mark fields that should be logged as event attributes:
mission_id: Annotated[str, EventAttr]
battery_level: Annotated[int, EventAttr]
Attributes:
| Name | Type | Description |
|---|---|---|
name |
Optional[str]
|
Optional custom name for the attribute (defaults to field name) |
SporesAttr
dataclass
¶
Metadata annotation for object attributes in OCEL object logging.
Used with typing.Annotated to mark fields that should be logged when an object is logged:
class Order(BaseModel):
id: str
status: Annotated[str, SporesAttr] # Logged
total: Annotated[float, SporesAttr] # Logged
items: list[dict] # Not marked - not logged
When using @spore.log_event(relationships={...}), fields marked with SporesAttr are automatically logged. If attributes list is provided, it overrides SporesAttr.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
Optional[str]
|
Optional custom name for the attribute (defaults to field name) |
ObjectLRUCache ¶
ObjectLRUCache(maxsize: int = 128, needs_logged: Optional[Callable[[K, Object], None]] = None, touch_resend_n: int = 100, metrics: Optional['CacheMetrics'] = None)
Bases: Generic[K, V]
LRU cache with unified callback for object logging.
The cache fires the needs_logged callback when an object needs to be logged:
- On first sight (new object added to cache)
- On eviction (object removed from cache to make room)
- When attributes change (detected via hash comparison)
- Every N touches (configurable via touch_resend_n)
This ensures OCEL consumers see object evolution: - First sight: Initial object state - Attribute changes: Updated state - Eviction: Final state before being removed from cache - Periodic resend: Long-lived objects are re-logged periodically
Example
def needs_logged(object_id: str, obj: Object):
# Send object to transport
transport.send(LogRecord(object=obj))
cache = ObjectLRUCache(maxsize=128, needs_logged=needs_logged, touch_resend_n=100)
# Check if object exists, add if not
if not cache.contains_or_add(object_id, object):
# Object not in cache, already logged by needs_logged
pass
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
maxsize
|
int
|
Maximum number of objects to cache |
128
|
needs_logged
|
Optional[Callable[[K, Object], None]]
|
Callback when object needs logging (object_id, object) -> None |
None
|
touch_resend_n
|
int
|
Resend object every N touches (0 to disable periodic resend) |
100
|
Source code in src/mycorrhizal/spores/cache.py
_evict_if_needed ¶
Evict oldest entry if cache is full.
Source code in src/mycorrhizal/spores/cache.py
get ¶
get(key: K) -> Optional[Object]
Get an object from the cache without updating its position.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
K
|
The object ID |
required |
Returns:
| Type | Description |
|---|---|
Optional[Object]
|
The Object if found, None otherwise |
Source code in src/mycorrhizal/spores/cache.py
get_and_touch ¶
get_and_touch(key: K) -> Optional[Object]
Get an object from the cache and mark it as recently used.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
K
|
The object ID |
required |
Returns:
| Type | Description |
|---|---|
Optional[Object]
|
The Object if found, None otherwise |
Source code in src/mycorrhizal/spores/cache.py
contains_or_add ¶
contains_or_add(key: K, obj: Object) -> bool
Check if key exists, add if not.
This is the primary method for object tracking: - If key exists: check for attribute changes, periodic resend, mark as recently used - If key doesn't exist: add object, potentially evict, log first sight
The needs_logged callback is fired when:
- First sight: new object added to cache
- Attribute change: object attributes changed (hash comparison)
- Every N touches: periodic resend for long-lived objects
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
K
|
The object ID |
required |
obj
|
Object
|
The OCEL Object to add if not present |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if object was already in cache, False if it was just added |
Source code in src/mycorrhizal/spores/cache.py
add ¶
add(key: K, obj: Object) -> None
Add an object to the cache (or update if exists).
Note: This method fires needs_logged for new objects, but not for updates. For attribute change detection and periodic resend, use contains_or_add().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
K
|
The object ID |
required |
obj
|
Object
|
The OCEL Object |
required |
Source code in src/mycorrhizal/spores/cache.py
remove ¶
remove(key: K) -> Optional[Object]
Remove an object from the cache.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
K
|
The object ID |
required |
Returns:
| Type | Description |
|---|---|
Optional[Object]
|
The removed Object, or None if key wasn't in cache |
clear ¶
__len__ ¶
__contains__ ¶
keys ¶
Encoder ¶
Bases: Protocol
Protocol for encoders that convert LogRecords to bytes.
Encoders serialize OCEL LogRecords for transport to OCEL consumers.
encode ¶
encode(record: LogRecord) -> bytes
Encode a LogRecord to bytes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record
|
LogRecord
|
The LogRecord to encode |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
Serialized bytes representation |
content_type ¶
Return the MIME content type for this encoding.
Returns:
| Type | Description |
|---|---|
str
|
Content type string (e.g., "application/json") |
JSONEncoder ¶
Bases: Encoder
JSON encoder for OCEL LogRecords.
Produces OCEL-compatible JSON with Unix float64 timestamps.
Example output
{ "event": { "id": "evt-123", "type": "process_item", "activity": null, "time": 1705689296.123456, "attributes": [ {"name": "priority", "value": "high", "type": "string"} ], "relationships": [ {"objectId": "obj-456", "qualifier": "input"} ] }, "object": null }
Or for objects
{ "event": null, "object": { "id": "obj-456", "type": "WorkItem", "attributes": [ {"name": "status", "value": "pending", "type": "string", "time": 1705689296.123456} ], "relationships": [] } }
Initialize JSONEncoder.
Timestamps are always encoded as Unix float64 timestamps.
Source code in src/mycorrhizal/spores/encoder/json.py
encode ¶
encode(record: LogRecord) -> bytes
Encode a LogRecord to JSON bytes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record
|
LogRecord
|
The LogRecord to encode |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
JSON-encoded bytes |
Source code in src/mycorrhizal/spores/encoder/json.py
content_type ¶
_event_to_dict ¶
_event_to_dict(event: Event) -> Dict[str, Any]
Convert an Event to dict for JSON serialization.
Source code in src/mycorrhizal/spores/encoder/json.py
_object_to_dict ¶
_object_to_dict(obj: Object) -> Dict[str, Any]
Convert an Object to dict for JSON serialization.
Source code in src/mycorrhizal/spores/encoder/json.py
_event_attr_to_dict ¶
_event_attr_to_dict(name: str, attr: EventAttributeValue) -> Dict[str, Any]
Convert EventAttributeValue to dict.
_object_attr_to_dict ¶
_object_attr_to_dict(name: str, attr: ObjectAttributeValue) -> Dict[str, Any]
Convert ObjectAttributeValue to dict.
Source code in src/mycorrhizal/spores/encoder/json.py
_relationship_to_dict ¶
_relationship_to_dict(qualifier: str, rel: Relationship) -> Dict[str, str]
_format_datetime ¶
Format datetime as Unix float64 timestamp.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dt
|
datetime
|
The datetime to format |
required |
Returns:
| Type | Description |
|---|---|
float
|
Unix float64 timestamp (seconds since epoch) |
Source code in src/mycorrhizal/spores/encoder/json.py
SyncTransport ¶
Bases: Protocol
Protocol for synchronous transports (blocking I/O).
Sync transports use blocking send() - they write data immediately and block until complete. Use these with get_spore_sync().
Examples: file writes, blocking HTTP requests, etc.
send ¶
Send encoded data to the transport destination (blocking).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
The encoded log record data |
required |
content_type
|
str
|
MIME content type (e.g., "application/json") |
required |
Source code in src/mycorrhizal/spores/transport/base.py
AsyncTransport ¶
Bases: Protocol
Protocol for asynchronous transports (async I/O).
Async transports use non-blocking async send() - they await completion. Use these with get_spore_async().
Examples: async file writes, async HTTP requests, message queues, etc.
send
async
¶
Send encoded data to the transport destination (async).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
The encoded log record data |
required |
content_type
|
str
|
MIME content type (e.g., "application/json") |
required |
Source code in src/mycorrhizal/spores/transport/base.py
SyncFileTransport ¶
Synchronous file transport using blocking I/O.
Writes log records to a file in JSONL format (one JSON object per line). Thread-safe with a lock for concurrent writes.
Initialize the file transport.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filepath
|
str | Path
|
Path to the log file. Will be created if it doesn't exist. |
required |
Source code in src/mycorrhizal/spores/transport/file.py
AsyncFileTransport ¶
Asynchronous file transport using async I/O.
Writes log records to a file in JSONL format (one JSON object per line). Uses asyncio.to_thread() for non-blocking async file I/O.
This is the async version of SyncFileTransport - use it with get_spore_async().
Initialize the async file transport.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filepath
|
str | Path
|
Path to the log file. Will be created if it doesn't exist. |
required |
Source code in src/mycorrhizal/spores/transport/file.py
send
async
¶
Write data to file asynchronously.
Uses asyncio.to_thread() to run blocking I/O in a thread pool, avoiding the need for external dependencies like aiofiles.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
Encoded log record data |
required |
content_type
|
str
|
MIME content type (e.g., "application/json") |
required |
Source code in src/mycorrhizal/spores/transport/file.py
_write_sync ¶
Synchronous write helper - runs in thread pool.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
Encoded log record data |
required |
close
async
¶
Close the file handle asynchronously.
__aenter__
async
¶
HyphaAdapter ¶
Adapter for Hypha Petri net logging.
Provides decorators and helpers for logging: - Transition execution with consumed/produced tokens - Place token arrivals/departures - Token object lifecycle tracking
Usage
from mycorrhizal.spores.dsl import HyphaAdapter
adapter = HyphaAdapter()
@pn.net
def MyNet(builder):
@builder.transition()
@adapter.log_transition(event_type="process_item")
async def process(consumed, bb, timebase):
# Event automatically logged with:
# - token_count attribute
# - relationships to consumed tokens
yield {output: consumed[0]}
@builder.place()
@adapter.log_place(event_type="item_arrived")
def input_place(bb):
return None
Initialize the Hypha adapter.
Source code in src/mycorrhizal/spores/dsl/hypha.py
enable ¶
disable ¶
log_transition ¶
log_transition(event_type: str, attributes: Optional[Union[Dict[str, Any], List[str]]] = None, log_inputs: bool = True, log_outputs: bool = False) -> Callable
Decorator to log Hypha transition execution.
Automatically captures: - Token count from consumed tokens - Relationships to consumed/produced tokens - Attributes from blackboard (if specified) - Objects from blackboard with ObjectRef metadata
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
Type of event to log |
required |
attributes
|
Optional[Union[Dict[str, Any], List[str]]]
|
Static attributes or param names to extract |
None
|
log_inputs
|
bool
|
Whether to log input tokens as related objects |
True
|
log_outputs
|
bool
|
Whether to log output tokens as related objects |
False
|
Returns:
| Type | Description |
|---|---|
Callable
|
Decorator function |
Source code in src/mycorrhizal/spores/dsl/hypha.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | |
log_place ¶
Decorator to log place token arrivals.
Note: This requires instrumenting the place handler or using a custom place runtime wrapper. For most cases, transition logging provides sufficient coverage.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
Type of event to log |
'token_arrived'
|
Returns:
| Type | Description |
|---|---|
Callable
|
Decorator function |
Source code in src/mycorrhizal/spores/dsl/hypha.py
RhizomorphAdapter ¶
Adapter for Rhizomorph behavior tree logging.
Provides decorators and helpers for logging: - Node tick execution with status results - Tree-level events - Blackboard object lifecycle tracking
Usage
from mycorrhizal.spores.dsl import RhizomorphAdapter
adapter = RhizomorphAdapter()
@bt.tree
def MyTree():
@bt.action
@adapter.log_node(event_type="check_threat")
async def check_threat(bb: MissionContext) -> Status:
# Event automatically logged with:
# - status result attribute
# - attributes from bb (with EventAttr annotations)
# - relationships to objects (with ObjectRef annotations)
return Status.SUCCESS
Initialize the Rhizomorph adapter.
Source code in src/mycorrhizal/spores/dsl/rhizomorph.py
enable ¶
disable ¶
log_node ¶
log_node(event_type: str, attributes: Optional[Union[Dict[str, Any], List[str]]] = None, log_status: bool = True) -> Callable
Decorator to log Rhizomorph node execution.
Automatically captures: - Node execution status (SUCCESS, FAILURE, RUNNING, etc.) - Attributes from blackboard (with EventAttr annotations) - Objects from blackboard (with ObjectRef annotations) - Node name
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
Type of event to log |
required |
attributes
|
Optional[Union[Dict[str, Any], List[str]]]
|
Static attributes or param names to extract |
None
|
log_status
|
bool
|
Whether to include status in event attributes |
True
|
Returns:
| Type | Description |
|---|---|
Callable
|
Decorator function |
Source code in src/mycorrhizal/spores/dsl/rhizomorph.py
SeptumAdapter ¶
Adapter for Septum state machine logging.
Provides decorators and helpers for logging: - State entry/exit/timeout events - State execution events - Transition events - Message/context object lifecycle tracking
Usage
from mycorrhizal.spores.dsl import SeptumAdapter
adapter = SeptumAdapter()
@septum.state()
def MyState():
@septum.on_state
@adapter.log_state(event_type="state_execute")
async def on_state(ctx: SharedContext):
# Event automatically logged with:
# - state_name attribute
# - attributes from ctx.common (with EventAttr annotations)
# - relationships to objects (with ObjectRef annotations)
return Events.DONE
@septum.on_enter
@adapter.log_state_lifecycle(event_type="state_enter")
async def on_enter(ctx: SharedContext):
pass
Initialize the Septum adapter.
Source code in src/mycorrhizal/spores/dsl/septum.py
enable ¶
disable ¶
log_state ¶
log_state(event_type: str, attributes: Optional[Dict[str, Any]] = None, log_state_name: bool = True, log_transition: bool = True) -> Callable
Decorator to log Septum state execution.
Automatically captures: - State name - Transition result (if log_transition=True) - Attributes from ctx.common (with EventAttr annotations) - Objects from ctx.common (with ObjectRef annotations) - Message information (if present in ctx)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
Type of event to log |
required |
attributes
|
Optional[Dict[str, Any]]
|
Static attributes to include |
None
|
log_state_name
|
bool
|
Whether to include state name in attributes |
True
|
log_transition
|
bool
|
Whether to include transition result |
True
|
Returns:
| Type | Description |
|---|---|
Callable
|
Decorator function |
Source code in src/mycorrhizal/spores/dsl/septum.py
log_state_lifecycle ¶
Decorator to log state lifecycle events (on_enter, on_leave, on_timeout).
Use this for logging lifecycle hooks rather than main state execution.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
Type of event to log (e.g., "state_enter", "state_leave") |
required |
attributes
|
Optional[Dict[str, Any]]
|
Static attributes to include |
None
|
Returns:
| Type | Description |
|---|---|
Callable
|
Decorator function |
Source code in src/mycorrhizal/spores/dsl/septum.py
configure ¶
configure(enabled: bool = True, object_cache_size: int = 128, encoder: Optional[Encoder] = None, transport: Optional[Transport] = None, eviction_policy: Union[EvictionPolicy, str] = EVICT_AND_LOG, touch_resend_n: int = 100) -> None
Configure the Spores logging system (thread-safe).
This should be called once at application startup. If called multiple times, the last call wins.
Thread-safe: Can be called from multiple threads concurrently.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
enabled
|
bool
|
Whether spores logging is enabled (default: True) |
True
|
object_cache_size
|
int
|
Maximum objects in LRU cache (default: 128) |
128
|
encoder
|
Optional[Encoder]
|
Encoder instance (defaults to JSONEncoder) |
None
|
transport
|
Optional[Transport]
|
Transport instance (required for logging to work) |
None
|
eviction_policy
|
Union[EvictionPolicy, str]
|
Policy for cache eviction (default: evict_and_log) |
EVICT_AND_LOG
|
touch_resend_n
|
int
|
Resend object every N touches (default: 100, 0 to disable) |
100
|
Example
Source code in src/mycorrhizal/spores/core.py
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | |
get_config ¶
get_config() -> SporesConfig
Get the current spores configuration (thread-safe).
If no configuration exists, creates a default one. Thread-safe: Can be called from multiple threads concurrently.
Source code in src/mycorrhizal/spores/core.py
get_object_cache ¶
get_object_cache() -> ObjectLRUCache[str, Object]
Get the object cache (thread-safe).
If no cache exists, initializes with default configuration. Thread-safe: Can be called from multiple threads concurrently.
Source code in src/mycorrhizal/spores/core.py
flush_object_cache ¶
Flush all objects from the cache to the log.
This forces all cached objects to be written, even if they haven't been evicted yet. Use this before application shutdown to ensure all objects are logged.
Thread-safe: Can be called from multiple threads concurrently.
Example
Source code in src/mycorrhizal/spores/core.py
get_cache_metrics ¶
get_cache_metrics() -> CacheMetrics
Get cache eviction metrics.
Returns statistics about cache evictions and failures.
Returns:
| Type | Description |
|---|---|
CacheMetrics
|
CacheMetrics with eviction statistics |
Example
Source code in src/mycorrhizal/spores/core.py
get_spore_sync ¶
get_spore_sync(name: str) -> SyncEventLogger
Get a synchronous spore logger.
Use this in synchronous code. The logger uses daemon threads for fire-and-forget logging - business logic never blocks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Spore name (typically module or name) |
required |
Returns:
| Type | Description |
|---|---|
SyncEventLogger
|
A SyncEventLogger instance |
Example
from mycorrhizal.spores import configure, get_spore_sync
from mycorrhizal.spores.transport import SyncFileTransport
configure(transport=SyncFileTransport("logs/ocel.jsonl"))
spore = get_spore_sync(__name__)
@spore.log_event(event_type="OrderCreated", order_id="order.id")
def create_order(order: Order) -> Order:
return order
Source code in src/mycorrhizal/spores/core.py
get_spore_async ¶
get_spore_async(name: str) -> AsyncEventLogger
Get an asynchronous spore logger.
Use this in asynchronous code. The logger uses async I/O.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Spore name (typically module or name) |
required |
Returns:
| Type | Description |
|---|---|
AsyncEventLogger
|
An AsyncEventLogger instance |
Example
from mycorrhizal.spores import configure, get_spore_async
from mycorrhizal.spores.transport import AsyncFileTransport
configure(transport=AsyncFileTransport("logs/ocel.jsonl"))
spore = get_spore_async(__name__)
@spore.log_event(event_type="OrderCreated", order_id="order.id")
async def create_order(order: Order) -> Order:
return order
Source code in src/mycorrhizal/spores/core.py
generate_event_id ¶
Generate a unique event ID.
Simple implementation using counter. Could be enhanced with UUIDs or more sophisticated schemes.
Returns:
| Type | Description |
|---|---|
str
|
A unique event identifier |
Source code in src/mycorrhizal/spores/models.py
generate_object_id ¶
Generate an object ID from an object.
Tries to use obj.id if available, otherwise generates a UUID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
obj
|
Any
|
The object to generate an ID for |
required |
Returns:
| Type | Description |
|---|---|
str
|
A unique object identifier |
Source code in src/mycorrhizal/spores/models.py
attribute_value_from_python ¶
attribute_value_from_python(value: Any) -> EventAttributeValue
Convert a Python value to an OCEL EventAttributeValue.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The Python value to convert |
required |
Returns:
| Type | Description |
|---|---|
EventAttributeValue
|
An EventAttributeValue with type information |
Source code in src/mycorrhizal/spores/models.py
object_attribute_from_python ¶
object_attribute_from_python(value: Any, time: Optional[datetime] = None) -> ObjectAttributeValue
Convert a Python value to an OCEL ObjectAttributeValue.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The Python value to convert |
required |
time
|
Optional[datetime]
|
The timestamp for this attribute value (optional) |
None
|
Returns:
| Type | Description |
|---|---|
ObjectAttributeValue
|
An ObjectAttributeValue with type information |
Source code in src/mycorrhizal/spores/models.py
Models¶
mycorrhizal.spores.models ¶
Spores Data Models
OCEL-compatible data models for event and object logging.
Relationship
dataclass
¶
A relationship from an event to an object.
Attributes:
| Name | Type | Description |
|---|---|---|
object_id |
str
|
The ID of the related object |
qualifier |
str
|
How the object relates to the event (e.g., "input", "output", "actor") |
EventAttributeValue
dataclass
¶
An attribute value for an event.
Event attributes don't have timestamps because the event time itself is sufficient.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The attribute name |
value |
str
|
The string representation of the value |
type |
str
|
The data type ("string", "integer", "float", "boolean", "timestamp") |
ObjectAttributeValue
dataclass
¶
An attribute value for an object.
OCEL attributes include timestamps for versioning.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The attribute name |
value |
str
|
The string representation of the value |
type |
str
|
The data type ("string", "integer", "float", "boolean", "timestamp") |
time |
Optional[datetime]
|
When this attribute value was set |
Event
dataclass
¶
Event(id: str, type: str, activity: Optional[str] = None, time: datetime = now(), attributes: Dict[str, EventAttributeValue] = dict(), relationships: Dict[str, Relationship] = dict())
An OCEL event representing something that happened.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
Unique event identifier |
type |
str
|
Event type/category (event class) |
activity |
Optional[str]
|
Optional semantic activity label (defaults to type if null) |
time |
datetime
|
When the event occurred |
attributes |
Dict[str, EventAttributeValue]
|
Event attributes (name -> EventAttributeValue) |
relationships |
Dict[str, Relationship]
|
Objects related to this event (qualifier -> Relationship) |
Object
dataclass
¶
Object(id: str, type: str, attributes: Dict[str, ObjectAttributeValue] = dict(), relationships: Dict[str, Relationship] = dict())
An OCEL object representing an entity in the system.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
Unique object identifier |
type |
str
|
Object type/category |
attributes |
Dict[str, ObjectAttributeValue]
|
Object attributes (name -> ObjectAttributeValue) |
relationships |
Dict[str, Relationship]
|
Other objects related to this object (qualifier -> Relationship) |
LogRecord
dataclass
¶
A log record containing either an event or an object (not both).
This is the union type used for streaming to OCEL consumers.
Attributes:
| Name | Type | Description |
|---|---|---|
event |
Optional[Event]
|
An event record (if logging an event) |
object |
Optional[Object]
|
An object record (if logging an object) |
Note
Exactly one of event or object must be set.
__post_init__ ¶
Validate that exactly one of event or object is set.
Source code in src/mycorrhizal/spores/models.py
ObjectScope ¶
Bases: Enum
Scope for object associations with events.
ObjectRef
dataclass
¶
ObjectRef(qualifier: str, scope: Union[ObjectScope, str] = EVENT)
Metadata annotation for object references in blackboard interfaces.
Used with typing.Annotated to mark fields as OCEL objects:
robot: Annotated[Robot, ObjectRef(qualifier="actor", scope=ObjectScope.GLOBAL)]
Attributes:
| Name | Type | Description |
|---|---|---|
qualifier |
str
|
How the object relates to events ("input", "output", "actor", etc.) |
scope |
Union[ObjectScope, str]
|
When to include this object in events |
__post_init__ ¶
EventAttr
dataclass
¶
Metadata annotation for event attributes in blackboard interfaces.
Used with typing.Annotated to mark fields that should be logged as event attributes:
mission_id: Annotated[str, EventAttr]
battery_level: Annotated[int, EventAttr]
Attributes:
| Name | Type | Description |
|---|---|---|
name |
Optional[str]
|
Optional custom name for the attribute (defaults to field name) |
SporesAttr
dataclass
¶
Metadata annotation for object attributes in OCEL object logging.
Used with typing.Annotated to mark fields that should be logged when an object is logged:
class Order(BaseModel):
id: str
status: Annotated[str, SporesAttr] # Logged
total: Annotated[float, SporesAttr] # Logged
items: list[dict] # Not marked - not logged
When using @spore.log_event(relationships={...}), fields marked with SporesAttr are automatically logged. If attributes list is provided, it overrides SporesAttr.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
Optional[str]
|
Optional custom name for the attribute (defaults to field name) |
infer_type ¶
Infer the OCEL type for a Python value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The Python value to infer type for |
required |
Returns:
| Type | Description |
|---|---|
str
|
One of: "string", "integer", "float", "boolean", "timestamp" |
Source code in src/mycorrhizal/spores/models.py
attribute_value_from_python ¶
attribute_value_from_python(value: Any) -> EventAttributeValue
Convert a Python value to an OCEL EventAttributeValue.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The Python value to convert |
required |
Returns:
| Type | Description |
|---|---|
EventAttributeValue
|
An EventAttributeValue with type information |
Source code in src/mycorrhizal/spores/models.py
object_attribute_from_python ¶
object_attribute_from_python(value: Any, time: Optional[datetime] = None) -> ObjectAttributeValue
Convert a Python value to an OCEL ObjectAttributeValue.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The Python value to convert |
required |
time
|
Optional[datetime]
|
The timestamp for this attribute value (optional) |
None
|
Returns:
| Type | Description |
|---|---|
ObjectAttributeValue
|
An ObjectAttributeValue with type information |
Source code in src/mycorrhizal/spores/models.py
generate_event_id ¶
Generate a unique event ID.
Simple implementation using counter. Could be enhanced with UUIDs or more sophisticated schemes.
Returns:
| Type | Description |
|---|---|
str
|
A unique event identifier |
Source code in src/mycorrhizal/spores/models.py
generate_object_id ¶
Generate an object ID from an object.
Tries to use obj.id if available, otherwise generates a UUID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
obj
|
Any
|
The object to generate an ID for |
required |
Returns:
| Type | Description |
|---|---|
str
|
A unique object identifier |
Source code in src/mycorrhizal/spores/models.py
Encoder¶
mycorrhizal.spores.encoder ¶
Spores Encoders
Encoders for serializing OCEL LogRecords to various formats.
Encoder ¶
Bases: Protocol
Protocol for encoders that convert LogRecords to bytes.
Encoders serialize OCEL LogRecords for transport to OCEL consumers.
encode ¶
encode(record: LogRecord) -> bytes
Encode a LogRecord to bytes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record
|
LogRecord
|
The LogRecord to encode |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
Serialized bytes representation |
content_type ¶
Return the MIME content type for this encoding.
Returns:
| Type | Description |
|---|---|
str
|
Content type string (e.g., "application/json") |
JSONEncoder ¶
Bases: Encoder
JSON encoder for OCEL LogRecords.
Produces OCEL-compatible JSON with Unix float64 timestamps.
Example output
{ "event": { "id": "evt-123", "type": "process_item", "activity": null, "time": 1705689296.123456, "attributes": [ {"name": "priority", "value": "high", "type": "string"} ], "relationships": [ {"objectId": "obj-456", "qualifier": "input"} ] }, "object": null }
Or for objects
{ "event": null, "object": { "id": "obj-456", "type": "WorkItem", "attributes": [ {"name": "status", "value": "pending", "type": "string", "time": 1705689296.123456} ], "relationships": [] } }
Initialize JSONEncoder.
Timestamps are always encoded as Unix float64 timestamps.
Source code in src/mycorrhizal/spores/encoder/json.py
encode ¶
encode(record: LogRecord) -> bytes
Encode a LogRecord to JSON bytes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record
|
LogRecord
|
The LogRecord to encode |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
JSON-encoded bytes |
Source code in src/mycorrhizal/spores/encoder/json.py
content_type ¶
_event_to_dict ¶
_event_to_dict(event: Event) -> Dict[str, Any]
Convert an Event to dict for JSON serialization.
Source code in src/mycorrhizal/spores/encoder/json.py
_object_to_dict ¶
_object_to_dict(obj: Object) -> Dict[str, Any]
Convert an Object to dict for JSON serialization.
Source code in src/mycorrhizal/spores/encoder/json.py
_event_attr_to_dict ¶
_event_attr_to_dict(name: str, attr: EventAttributeValue) -> Dict[str, Any]
Convert EventAttributeValue to dict.
_object_attr_to_dict ¶
_object_attr_to_dict(name: str, attr: ObjectAttributeValue) -> Dict[str, Any]
Convert ObjectAttributeValue to dict.
Source code in src/mycorrhizal/spores/encoder/json.py
_relationship_to_dict ¶
_relationship_to_dict(qualifier: str, rel: Relationship) -> Dict[str, str]
_format_datetime ¶
Format datetime as Unix float64 timestamp.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dt
|
datetime
|
The datetime to format |
required |
Returns:
| Type | Description |
|---|---|
float
|
Unix float64 timestamp (seconds since epoch) |
Source code in src/mycorrhizal/spores/encoder/json.py
Transport¶
mycorrhizal.spores.transport ¶
Spores Transports
Transports for sending OCEL LogRecords to various destinations.
SyncTransport ¶
Bases: Protocol
Protocol for synchronous transports (blocking I/O).
Sync transports use blocking send() - they write data immediately and block until complete. Use these with get_spore_sync().
Examples: file writes, blocking HTTP requests, etc.
send ¶
Send encoded data to the transport destination (blocking).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
The encoded log record data |
required |
content_type
|
str
|
MIME content type (e.g., "application/json") |
required |
Source code in src/mycorrhizal/spores/transport/base.py
AsyncTransport ¶
Bases: Protocol
Protocol for asynchronous transports (async I/O).
Async transports use non-blocking async send() - they await completion. Use these with get_spore_async().
Examples: async file writes, async HTTP requests, message queues, etc.
send
async
¶
Send encoded data to the transport destination (async).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
The encoded log record data |
required |
content_type
|
str
|
MIME content type (e.g., "application/json") |
required |
Source code in src/mycorrhizal/spores/transport/base.py
SyncFileTransport ¶
Synchronous file transport using blocking I/O.
Writes log records to a file in JSONL format (one JSON object per line). Thread-safe with a lock for concurrent writes.
Initialize the file transport.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filepath
|
str | Path
|
Path to the log file. Will be created if it doesn't exist. |
required |
Source code in src/mycorrhizal/spores/transport/file.py
AsyncFileTransport ¶
Asynchronous file transport using async I/O.
Writes log records to a file in JSONL format (one JSON object per line). Uses asyncio.to_thread() for non-blocking async file I/O.
This is the async version of SyncFileTransport - use it with get_spore_async().
Initialize the async file transport.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filepath
|
str | Path
|
Path to the log file. Will be created if it doesn't exist. |
required |
Source code in src/mycorrhizal/spores/transport/file.py
send
async
¶
Write data to file asynchronously.
Uses asyncio.to_thread() to run blocking I/O in a thread pool, avoiding the need for external dependencies like aiofiles.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
Encoded log record data |
required |
content_type
|
str
|
MIME content type (e.g., "application/json") |
required |
Source code in src/mycorrhizal/spores/transport/file.py
_write_sync ¶
Synchronous write helper - runs in thread pool.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
Encoded log record data |
required |
close
async
¶
Close the file handle asynchronously.
__aenter__
async
¶
DSL Adapters¶
mycorrhizal.spores.dsl ¶
Spores DSL Adapters
DSL-specific adapters for integrating spores logging with: - Hypha (Petri nets) - Rhizomorph (Behavior trees) - Septum (State machines)
Usage
from mycorrhizal.spores.dsl import HyphaAdapter, RhizomorphAdapter, SeptumAdapter
# For Hypha (Petri nets)
hypha_adapter = HyphaAdapter()
@pn.transition()
@hypha_adapter.log_transition(event_type="process")
async def process(consumed, bb, timebase):
yield {output: consumed[0]}
# For Rhizomorph (Behavior trees)
rhizo_adapter = RhizomorphAdapter()
@bt.action
@rhizo_adapter.log_node(event_type="check")
async def check(bb: Blackboard) -> Status:
return Status.SUCCESS
# For Septum (State machines)
septum_adapter = SeptumAdapter()
@septum.on_state
@septum_adapter.log_state(event_type="state_execute")
async def on_state(ctx: SharedContext):
return Events.DONE
HyphaAdapter ¶
Adapter for Hypha Petri net logging.
Provides decorators and helpers for logging: - Transition execution with consumed/produced tokens - Place token arrivals/departures - Token object lifecycle tracking
Usage
from mycorrhizal.spores.dsl import HyphaAdapter
adapter = HyphaAdapter()
@pn.net
def MyNet(builder):
@builder.transition()
@adapter.log_transition(event_type="process_item")
async def process(consumed, bb, timebase):
# Event automatically logged with:
# - token_count attribute
# - relationships to consumed tokens
yield {output: consumed[0]}
@builder.place()
@adapter.log_place(event_type="item_arrived")
def input_place(bb):
return None
Initialize the Hypha adapter.
Source code in src/mycorrhizal/spores/dsl/hypha.py
enable ¶
disable ¶
log_transition ¶
log_transition(event_type: str, attributes: Optional[Union[Dict[str, Any], List[str]]] = None, log_inputs: bool = True, log_outputs: bool = False) -> Callable
Decorator to log Hypha transition execution.
Automatically captures: - Token count from consumed tokens - Relationships to consumed/produced tokens - Attributes from blackboard (if specified) - Objects from blackboard with ObjectRef metadata
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
Type of event to log |
required |
attributes
|
Optional[Union[Dict[str, Any], List[str]]]
|
Static attributes or param names to extract |
None
|
log_inputs
|
bool
|
Whether to log input tokens as related objects |
True
|
log_outputs
|
bool
|
Whether to log output tokens as related objects |
False
|
Returns:
| Type | Description |
|---|---|
Callable
|
Decorator function |
Source code in src/mycorrhizal/spores/dsl/hypha.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | |
log_place ¶
Decorator to log place token arrivals.
Note: This requires instrumenting the place handler or using a custom place runtime wrapper. For most cases, transition logging provides sufficient coverage.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
Type of event to log |
'token_arrived'
|
Returns:
| Type | Description |
|---|---|
Callable
|
Decorator function |
Source code in src/mycorrhizal/spores/dsl/hypha.py
RhizomorphAdapter ¶
Adapter for Rhizomorph behavior tree logging.
Provides decorators and helpers for logging: - Node tick execution with status results - Tree-level events - Blackboard object lifecycle tracking
Usage
from mycorrhizal.spores.dsl import RhizomorphAdapter
adapter = RhizomorphAdapter()
@bt.tree
def MyTree():
@bt.action
@adapter.log_node(event_type="check_threat")
async def check_threat(bb: MissionContext) -> Status:
# Event automatically logged with:
# - status result attribute
# - attributes from bb (with EventAttr annotations)
# - relationships to objects (with ObjectRef annotations)
return Status.SUCCESS
Initialize the Rhizomorph adapter.
Source code in src/mycorrhizal/spores/dsl/rhizomorph.py
enable ¶
disable ¶
log_node ¶
log_node(event_type: str, attributes: Optional[Union[Dict[str, Any], List[str]]] = None, log_status: bool = True) -> Callable
Decorator to log Rhizomorph node execution.
Automatically captures: - Node execution status (SUCCESS, FAILURE, RUNNING, etc.) - Attributes from blackboard (with EventAttr annotations) - Objects from blackboard (with ObjectRef annotations) - Node name
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
Type of event to log |
required |
attributes
|
Optional[Union[Dict[str, Any], List[str]]]
|
Static attributes or param names to extract |
None
|
log_status
|
bool
|
Whether to include status in event attributes |
True
|
Returns:
| Type | Description |
|---|---|
Callable
|
Decorator function |
Source code in src/mycorrhizal/spores/dsl/rhizomorph.py
SeptumAdapter ¶
Adapter for Septum state machine logging.
Provides decorators and helpers for logging: - State entry/exit/timeout events - State execution events - Transition events - Message/context object lifecycle tracking
Usage
from mycorrhizal.spores.dsl import SeptumAdapter
adapter = SeptumAdapter()
@septum.state()
def MyState():
@septum.on_state
@adapter.log_state(event_type="state_execute")
async def on_state(ctx: SharedContext):
# Event automatically logged with:
# - state_name attribute
# - attributes from ctx.common (with EventAttr annotations)
# - relationships to objects (with ObjectRef annotations)
return Events.DONE
@septum.on_enter
@adapter.log_state_lifecycle(event_type="state_enter")
async def on_enter(ctx: SharedContext):
pass
Initialize the Septum adapter.
Source code in src/mycorrhizal/spores/dsl/septum.py
enable ¶
disable ¶
log_state ¶
log_state(event_type: str, attributes: Optional[Dict[str, Any]] = None, log_state_name: bool = True, log_transition: bool = True) -> Callable
Decorator to log Septum state execution.
Automatically captures: - State name - Transition result (if log_transition=True) - Attributes from ctx.common (with EventAttr annotations) - Objects from ctx.common (with ObjectRef annotations) - Message information (if present in ctx)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
Type of event to log |
required |
attributes
|
Optional[Dict[str, Any]]
|
Static attributes to include |
None
|
log_state_name
|
bool
|
Whether to include state name in attributes |
True
|
log_transition
|
bool
|
Whether to include transition result |
True
|
Returns:
| Type | Description |
|---|---|
Callable
|
Decorator function |
Source code in src/mycorrhizal/spores/dsl/septum.py
log_state_lifecycle ¶
Decorator to log state lifecycle events (on_enter, on_leave, on_timeout).
Use this for logging lifecycle hooks rather than main state execution.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_type
|
str
|
Type of event to log (e.g., "state_enter", "state_leave") |
required |
attributes
|
Optional[Dict[str, Any]]
|
Static attributes to include |
None
|
Returns:
| Type | Description |
|---|---|
Callable
|
Decorator function |