refcodes-schema: Canonical runtime diagnostics and visitor-based reports

README

The REFCODES.ORG codes represent a group of artifacts consolidating parts of my work in the past years. Several topics are covered which I consider useful for you, programmers, developers and software engineers.

What is this repository for?

This artifact defines a lightweight canonical schema for representing a system’s runtime state and offers visitor interfaces to export that state in multiple notations.

It helps you understand and diagnose complex object graphs without invasive debugging or excessive logging. You model your data as nested Schema instances, optionally expose a simple Schemable façade on your types, and let visitors render the result.

How do I get set up?

To get up and running, include the following dependency (without the three dots “…”) in your pom.xml:

1
2
3
4
5
6
7
8
9
<dependencies>
	...
	<dependency>
		<artifactId>refcodes-schema</artifactId>
		<groupId>org.refcodes</groupId>
		<version>3.4.1</version>
	</dependency>
	...
</dependencies>

The artifact is hosted directly at Maven Central. Jump straight to the source codes at Bitbucket. Read the artifact’s javadoc at javadoc.io.

1
2
3
4
5
6
7
8
9
<dependencies>
	...
	<dependency>
		<artifactId>refcodes-schema-alt-introspection</artifactId>
		<groupId>org.refcodes</groupId>
		<version>3.4.1</version>
	</dependency>
	...
</dependencies>

The artifact is hosted directly at Maven Central. Jump straight to the source codes at Bitbucket. Read the artifact’s javadoc at javadoc.io.

How do I get started?

The core pieces are:

  • Schema A canonical container for diagnostic data. Holds key/value properties, an optional instance reference, and child Schema nodes to form a hierarchy.

  • Schemable An interface for types that can expose their diagnostic view via toSchema().

  • SchemaVisitor<R> A visitor that traverses a Schema tree and produces an output of type R. Implementations include JSON, XML, and PlantUML exporters.

Canonical model

You capture runtime state as a nested tree of Schema nodes. Each node can store arbitrary properties (key/value), and may have child nodes for contained or related data. This yields a consistent, tool-friendly view across subsystems.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public final class SensorReading implements Schemable {

  private final String name;
  private final int value;

  public SensorReading(String name, int value) {
    this.name = name;
    this.value = value;
  }

  @Override
  public Schema toSchema() {
    return Schema.builder()
        .withAlias("sensorReading")
        .withInstance(this)
        .withDescription("A single sensor reading")
        .withProperty("name", name)
        .withProperty("value", Integer.toString(value))
        .build();
  }
}

Composites simply aggregate their children’s Schema:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public final class SensorPanel implements Schemable {

  private final List<SensorReading> sensors;

  public SensorPanel(List<SensorReading> sensors) {
    this.sensors = sensors;
  }

  @Override
  public Schema toSchema() {
    var childSchemas = sensors.stream()
        .map(Schemable::toSchema)
        .toArray(Schema[]::new);

    return Schema.builder()
        .withAlias("sensorPanel")
        .withInstance(this)
        .withDescription("Panel with multiple sensors")
        .withChildren(childSchemas)
        .build()
        .withProperty("count", Integer.toString(sensors.size()));
  }
}

Export with visitors

Once you have a Schema, you can render it in different formats by supplying the corresponding visitor:

1
2
3
4
5
Schema schema = panel.toSchema();

String json = schema.visit(new JsonVisitor());
String xml  = schema.visit(new XmlVisitor());
String puml = schema.visit(new PlantUmlVisitor());
  • JSON/XML give you machine-readable diagnostics for pipelines, dashboards, and reports
  • PlantUML gives you diagrams that visualize object graphs for faster human understanding

Serving diagnostics via an interface

You can expose diagnostics safely without enabling full debug mode. For example, via Spring Boot Actuator:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component
@WebEndpoint(id = "diagnostics")
public class DiagnosticsEndpoint {

  private final Schemable root; // Provide your root of interest

  public DiagnosticsEndpoint(Schemable root) { this.root = root; }

  @ReadOperation
  public WebEndpointResponse<String> plantUml() {
    Schema schema = root.toSchema();
    String puml = schema.visit(new PlantUmlVisitor());
    return new WebEndpointResponse<>(puml, 200, "text/x-plantuml");
  }
}

Alternatively, expose the same data via an MBean and access it with JMX tools such as JConsole.

Snippets of interest

Add ad-hoc properties

1
2
3
4
5
6
7
Schema schema = Schema.builder()
    .withAlias("job")
    .withDescription("Batch job diagnostics")
    .build()
    .withProperty("id", jobId)
    .withProperty("status", status)
    .withProperty("durationMs", Long.toString(duration));

Compose hierarchies

1
2
3
4
Schema root = Schema.builder()
    .withAlias("orderProcessing")
    .withChildren(order.toSchema(), inventory.toSchema(), payment.toSchema())
    .build();

Render and persist

1
2
3
4
5
6
String xml  = root.visit(new XmlVisitor());
String json = root.visit(new JsonVisitor());

// Write to disk or attach to tickets
Files.writeString(Path.of("diag.xml"), xml);
Files.writeString(Path.of("diag.json"), json);

Visualize with PlantUML

1
2
String puml = root.visit(new PlantUmlVisitor());
// Feed into a PlantUML renderer to produce a diagram for your runbook

Design considerations

  • Separation of concerns Diagnostics are modeled once as a canonical schema. Export formats are independent visitors.

  • Low overhead Simple POJOs implement Schemable. No heavy dependencies or annotations required.

  • Extensibility Add your own SchemaVisitor for custom formats or targets.

  • Operational safety Expose read-only snapshots via endpoints or JMX without attaching debuggers or flooding logs.

Examples

For examples and usage, please take a look at the according Unit-Tests here. For examples and usage on the introspection alternative, please take a look at the according Unit-Tests here.

See also

Contribution guidelines

  • Report issues
  • Finding bugs
  • Helping fixing bugs
  • Making code and documentation better
  • Enhance the code

Who do I talk to?

  • Siegfried Steiner (steiner@refcodes.org)

Terms and conditions

The REFCODES.ORG group of artifacts is published under some open source licenses; covered by the refcodes-licensing (org.refcodes group) artifact - evident in each artifact in question as of the pom.xml dependency included in such artifact.