Skip to main content

Generating Reports from Logs

Problem Definition

From Log Data to Human-Readable Reports

When executing workflows with actor-IaC, various data is recorded in logs:

  • Workflow execution history (Transitions)
  • System information collected from each node (JsonState)
  • Data accumulated with % notation

We want to convert this log data into human-readable reports suited for specific purposes.

Requirements:

  1. Pluggable - Compose reports by combining sections
  2. Purpose-specific reports - Alert reports, system overview reports, etc.
  3. Assembled in workflow YAML - Change report composition without code changes

Limitations of "Built-in" Design

Traditional ReportBuilder had a fixed design:

reportBuilder.addWorkflowInfo()     // Fixed format
reportBuilder.addJsonStateSection() // Fixed format
reportBuilder.report() // Fixed output

To change the output format, you had to modify ReportBuilder itself or create a separate class.


How to do it

Section Plugin Approach

Place section builders as child actors of ReportBuilder, and determine the combination in workflow YAML.

ROOT
└── reportBuilder
├── wfName ← Workflow name
├── wfDesc ← Workflow description
└── nodeData ← Node data

Basic Usage

Workflow example:

name: basic-report

steps:
# 1. Create ReportBuilder and section builders
- states: ["0", "1"]
note: Create ReportBuilder and sections
actions:
- actor: loader
method: createChild
arguments: ["ROOT", "reportBuilder", "com.scivicslab.actoriac.report.ReportBuilderIIAR"]
- actor: loader
method: createChild
arguments: ["reportBuilder", "wfName", "com.scivicslab.actoriac.report.sections.basic.WorkflowNameSectionIIAR"]
- actor: loader
method: createChild
arguments: ["reportBuilder", "wfDesc", "com.scivicslab.actoriac.report.sections.basic.WorkflowDescriptionSectionIIAR"]

# 2. Data collection (execute sub-workflow on each node)
- states: ["1", "2"]
note: Collect system info
actions:
- actor: nodeGroup
method: apply
arguments:
actor: "node-*"
method: runWorkflow
arguments: ["collect-sysinfo.yaml"]

# 3. Generate report
- states: ["2", "end"]
note: Generate report
actions:
- actor: reportBuilder
method: report

Available Section Builders

Standard sections included in actor-IaC (core):

Sections are output in the order they were createChild'd.

IIAR ClassWhat it outputs
WorkflowNameSectionIIARWorkflow name (YAML name field)
WorkflowFileSectionIIARWorkflow file path
WorkflowDescriptionSectionIIARWorkflow description (YAML description field)
CheckResultsSectionIIARCollects lines output with % notation
JsonStateSectionIIAROutputs specified actor's JsonState in YAML format
TransitionHistorySectionIIARWorkflow state transition history
GpuSummarySectionIIARGPU information summary (NVIDIA/AMD)

All classes are in the com.scivicslab.actoriac.report.sections.basic package.

actor-IaC-plugins (optional):

Currently, no SectionBuilder plugins are provided. For creating custom sections, refer to Plugin Development.

Purpose-Specific Report Examples

Deployment result report:

name: deployment-report

steps:
- states: ["0", "1"]
note: Create ReportBuilder and sections
actions:
- actor: loader
method: createChild
arguments: ["ROOT", "reportBuilder", "...ReportBuilderIIAR"]
- actor: loader
method: createChild
arguments: ["reportBuilder", "wfName", "...WorkflowNameSectionIIAR"]
- actor: loader
method: createChild
arguments: ["reportBuilder", "wfDesc", "...WorkflowDescriptionSectionIIAR"]
- actor: loader
method: createChild
arguments: ["reportBuilder", "checkResults", "...CheckResultsSectionIIAR"]
- actor: loader
method: createChild
arguments: ["reportBuilder", "trans:nodeGroup:children", "...TransitionHistorySectionIIAR"]

- states: ["1", "2"]
note: Deploy
actions:
- actor: nodeGroup
method: apply
arguments:
actor: "node-*"
method: runWorkflow
arguments: ["deploy.yaml"]

- states: ["2", "end"]
actions:
- actor: reportBuilder
method: report

System status report:

name: system-status-report

steps:
- states: ["0", "1"]
note: Create ReportBuilder with state sections
actions:
- actor: loader
method: createChild
arguments: ["ROOT", "reportBuilder", "...ReportBuilderIIAR"]
- actor: loader
method: createChild
arguments: ["reportBuilder", "wfName", "...WorkflowNameSectionIIAR"]
- actor: loader
method: createChild
arguments: ["reportBuilder", "wfFile", "...WorkflowFileSectionIIAR"]
- actor: loader
method: createChild
arguments: ["reportBuilder", "state:nodeGroup:cluster", "...JsonStateSectionIIAR"]
- actor: loader
method: createChild
arguments: ["reportBuilder", "gpuSummary", "...GpuSummarySectionIIAR"]

- states: ["1", "2"]
note: Collect system info
actions:
- actor: nodeGroup
method: apply
arguments:
actor: "node-*"
method: runWorkflow
arguments: ["collect-sysinfo.yaml"]

- states: ["2", "end"]
actions:
- actor: reportBuilder
method: report

Output Destinations

Reports are output via outputMultiplexer. That means:

  • Console - Real-time viewing
  • File - When --file-log option is specified
  • Database - Structured storage in H2 DB

Reports themselves are also saved as logs, so they can be referenced later.


Under the hood

POJO and IIActorRef Separation Design

Section builders are implemented with separation of POJO (business logic) and IIAR (actor layer).

Design principles:

  1. POJO is pure POJO - Does not implement CallableByActionName
  2. IIAR handles action exposure - Exposes methods with @Action annotation
  3. String argument constraint - Ensures messaging in distributed actor systems

Class structure example:

WorkflowNameSection (POJO)
- String generate() // Business logic
- String getTitle()

WorkflowNameSectionIIAR extends IIActorRef<WorkflowNameSection>
- @Action("generate") // Calls POJO method
- @Action("getTitle")

SectionBuilder Interface (POJO)

/**
* POJO interface for section builders.
* Does not inherit CallableByActionName.
*/
public interface SectionBuilder {

/** Generate section content */
String generate();

/** Section title (null to omit) */
default String getTitle() { return null; }
}

ReportBuilder Operation

The report action of ReportBuilder calls the generate action of child actors in order of addition.

// Overview of ReportBuilder.build()
public String build() {
StringBuilder sb = new StringBuilder();
sb.append("=== Workflow Execution Report ===\n");

// Collect sections from child actors (in order of addition)
for (String childName : selfRef.getNamesOfChildren()) {
IIActorRef<?> child = system.getIIActor(childName);

// Call generate action
ActionResult result = child.callByActionName("generate", "");
if (result.isSuccess()) {
String content = result.getResult();
String title = getTitle(child);
appendSection(sb, title, content);
}
}

return sb.toString();
}

This section contains detailed documentation for each SectionBuilder:

DocumentDescription
WorkflowNameSectionOutputs workflow name
WorkflowDescriptionSectionOutputs workflow description
WorkflowFileSectionOutputs workflow file path
CheckResultsSectionCollects % notation output
JsonStateSectionOutputs JsonState in YAML format
TransitionHistorySectionOutputs state transition history
GpuSummarySectionSummarizes GPU information
Actor Tree in ReportIncluding actor tree in reports