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 ReportBuilder and each SectionBuilder:

DocumentDescription
ReportBuilder BasicsBasic usage of loader, ReportBuilder, and SectionBuilder
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