Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ _site
vendor
.DS_Store
node_modules/
.idea
.idea
*~
110 changes: 110 additions & 0 deletions src/_backend/logging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
title: Understanding the SwimOS logging API
short-title: Logging
description: "Making use of the SwimOS logging interface from various contexts."
group: Reference
layout: documentation
redirect_from:
- /tutorials/logging/
---

The public interface for logging, <a href="swim-java/swim-runtime/swim-core/swim.util/src/main/java/swim/util/Log.java" target="_blank">`swim.util.Log`</a> defines six methods, all of which return `void` and take single parameter of type `Objecct`. Here is an example:

```
void trace(Object message);
```

The supported methods, from lowest to high, are:

- trace: Logs a trace-level message.
- debug: Logs a debug-level message.
- info: Logs an info-level message.
- warn: Logs a warn-level message.
- error: Logs an error-level message.
- fail: Logs an fail-level message.

This interface can be found on several classes, such as `AbstractPlane`, `AbstractAgent`, and all of the lane types, such as `CommandLane`, `ValueLane`, and `MapLane`. Implementation-wise, they will ultimately print the message passed down, so additional enhancement to show context such as agent, host, node, and lane can be accomplished using a wrapper within your Web Agent implementation.

Invoking a log method within a Web Agent method might look like this:

```
info("SpecialAgent initialized for " + nodeUri());
```

### Example

Let's consider a simple example that illustrates logging from various contexts.

#### `src/main/resources/server.recon`

```
logville: @fabric {
@plane(class: "logville.MainPlane")

@node {
uri: "/lonewolf"
@agent(class: "logville.Agent")
}
}
@web(port: 9001) {
space: "logville"
}
```

#### `src/main/java/logville/MainPlane.java`

```
package logville;

import swim.api.plane.AbstractPlane;
import swim.kernel.Kernel;
import swim.server.ServerLoader;
import swim.structure.Text;

public class MainPlane extends AbstractPlane {

public static void main(String[] args) {
final Kernel kernel = ServerLoader.loadServer();
System.out.println("Starting server...");
kernel.start();
System.out.println("Running server...");
kernel.run();
}

@Override
public void didStart() {
this.info("Hello, world, from MainPlane!"); // the Log interface is invoked on `AbstractPlane`
command("/lonewolf", "howl", Text.from("Auuuuu!"));
}
}
```

#### `src/main/java/logville/Agent.java`

```
package logville;

import swim.api.SwimLane;
import swim.api.agent.AbstractAgent;
import swim.api.lane.CommandLane;

public class Agent extends AbstractAgent {

@SwimLane("howl")
CommandLane<String> howl = this.<String>commandLane()
.onCommand(message -> this.info(nodeUri() + ": howl: " + message)); // the Log interface is invoked on AbstractLane

@Override
public void didStart() {
this.info(nodeUri() + ": Hello, agent!"); // the Log interface is invoked on AbstractAgent
}

}
```

### Conclusion

The Swim logging API offers a flexible and intuitive mechanism for logging within the SwimOS framework. By utilizing the swim.util.Log interface that exists on common objects in the SwimOS ecosystem, you can easily integrate logging into your applications, whether it be on planes, agents, or lanes. The range of log levels from trace to fail allows for detailed categorization of log messages, ensuring that the right amount of information is captured for various scenarios. Logging is a critical part of any application for monitoring, debugging, and maintaining healthy system operations. In Swim applications, this becomes even more crucial due to the dynamic and distributed nature of the system.

By incorporating contextual information such as node URIs and agent specifics into log messages, you can gain a clearer and more comprehensive understanding of your system's behavior and performance. This capability enhances the observability of the SwimOS application, making it easier to diagnose issues and understand system interactions.

103 changes: 103 additions & 0 deletions src/_posts/2023-11-28-logging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Understanding the Swim logging API

The public interface for logging, <a href="swim-java/swim-runtime/swim-core/swim.util/src/main/java/swim/util/Log.java" target="_blank">`swim.util.Log`</a> defines six methods, all of which return `void` and take a single parameter of type `Object`. Given the real-time, high-performance aspect, SwimOS logging is non-blocking. In addition to conventional logging, you can also access agent-specific performance logs with SwimOS's <a target="_blank" href="https://www.swimos.org/backend/introspection/">introspection</a> layer. You can think of introspection</a> as an observability layer that lets you understand how your agents are performing. With introspection, you can stream the debug logs or the info logs for a specific agent using the introspection APIs. You can stream the debug and info logs from introspection. Here's an <a target="_blank" href="https://github.com/swimos/swim-cellular?tab=readme-ov-file#log-introspection">example</a> of how to do it using the <a target="_blank" href="https://www.swimos.org/backend/cli/">`swim-cli`</a> tool.

Let's look at the basic logging API now.

```
void trace(Object message);
```

The supported methods, from lowest to high, are:

- trace: Logs a trace-level message.
- debug: Logs a debug-level message.
- info: Logs an info-level message.
- warn: Logs a warn-level message.
- error: Logs an error-level message.
- fail: Logs a fail-level message.

This interface can be found on several classes, such as `AbstractPlane`, `AbstractAgent`, and all of the lane types, such as `CommandLane`, `ValueLane`, and `MapLane`. Implementation-wise, they will ultimately print the message passed down, so additional enhancement to show context such as agent, host, node, and lane can be accomplished using a wrapper within your Web Agent implementation.

Invoking a log method within a Web Agent method might look like this:

```
info("SpecialAgent initialized for " + nodeUri());
```

## Example

Let's consider a simple example that illustrates logging from various contexts.

### `src/main/resources/server.recon`

```
logville: @fabric {
@plane(class: "logville.MainPlane")

@node {
uri: "/lonewolf"
@agent(class: "logville.Agent")
}
}
@web(port: 9001) {
space: "logville"
}
```

### `src/main/java/logville/MainPlane.java`

```
package logville;

import swim.api.plane.AbstractPlane;
import swim.kernel.Kernel;
import swim.server.ServerLoader;
import swim.structure.Text;

public class MainPlane extends AbstractPlane {

public static void main(String[] args) {
final Kernel kernel = ServerLoader.loadServer();
System.out.println("Starting server...");
kernel.start();
System.out.println("Running server...");
kernel.run();
}

@Override
public void didStart() {
this.info("Hello, world, from MainPlane!"); // the Log interface is invoked on `AbstractPlane`
command("/lonewolf", "howl", Text.from("Auuuuu!"));
}
}
```

### `src/main/java/logville/Agent.java`

```
package logville;

import swim.api.SwimLane;
import swim.api.agent.AbstractAgent;
import swim.api.lane.CommandLane;

public class Agent extends AbstractAgent {

@SwimLane("howl")
CommandLane<String> howl = this.<String>commandLane()
.onCommand(message -> this.info(nodeUri() + ": howl: " + message)); // the Log interface is invoked on AbstractLane

@Override
public void didStart() {
this.info(nodeUri() + ": Hello, agent!"); // the Log interface is invoked on AbstractAgent
}

}
```

## Conclusion

The Swim logging API offers a flexible and intuitive mechanism for logging within the SwimOS framework. By utilizing the swim.util.Log interface that exists on common objects in the SwimOS ecosystem, you can easily integrate logging into your applications, whether it be on planes, agents, or lanes. The range of log levels from trace to fail allows for detailed categorization of log messages, ensuring that the right amount of information is captured for various scenarios. Logging is a critical part of any application for monitoring, debugging, and maintaining healthy system operations. In Swim applications, this becomes even more crucial due to the dynamic and distributed nature of the system.

By incorporating contextual information such as node URIs and agent specifics into log messages, you can gain a clearer and more comprehensive understanding of your system's behavior and performance. This capability enhances the observability of the SwimOS application, making it easier to diagnose issues and understand system interactions.