-
Notifications
You must be signed in to change notification settings - Fork 7
Home
1. n. A one-sided conversation.
Monologue is a Java annotation-based logging library for FRC. With Monologue, extensive telemetry and on-robot logging can be added to your robot code with minimal code footprint and design restrictions.
For teams already familiar with Oblog, the setup process for Monologue is very similar.
The first step to using Monologue is to add it to your robot project as a dependency. Monologue is distributed using jitpack.
To add the dependency, we only need to add a couple lines to your project’s build.gradle. First, add the following:
repositories {
maven { url 'https://jitpack.io' }
}
Secondly, add the following to the dependencies
list:
implementation 'com.github.shueja:Monologue:RELEASE_TAG'
where RELEASE_TAG is the latest release version tag (e.g. v1.0.0).
The first step of setting up Monologue is choosing a base class. Robot.java
is a good choice for this, though for command-based teams, RobotContainer.java
is a good alternative. The important part is to setup the logger after all contained classes have been constructed, typically at the end of robotInit()
or the RobotContainer
constructor. Your base class needs to implement monologue.Logged
, so that Monologue can create a level in the logging structure for it.
A basic configuration for a simple TimedRobot project would be like this:
package frc.robot;
import monologue.Monologue;
import monologue.Logged;
public class Robot extends TimedRobot implements Logged {
@Override
public void robotInit() {
...
boolean fileOnly = false;
boolean lazyLogging = false;
Monologue.setupMonologue(this, "Robot", fileOnly, lazyLogging);
}
@Override
public void robotPeriodic() {
// setFileOnly is used to shut off NetworkTables broadcasting for most logging calls.
// Basing this condition on the connected state of the FMS is a suggestion only.
Monologue.setFileOnly(DriverStation.isFMSConnected());
Monologue.updateAll();
}
}
The first argument to Monologue.setupLogging()
is the root Logged
class, which is Robot, or this
. The second argument is the path to use for the root container. In this case, values being logged would show up in NetworkTables and DataLog under /Robot/variableName
.
IMPORTANT: Forward slashes as path separators is permitted in the
rootPath
. However, do not start yourrootPath
with more than one leading forward slash. Monologue will accept/Robot
orRobot
as the same path (and will add a slash if necessary to log under/Robot
). However, additional leading slashes lead to client-dependent display behavior and should generally be avoided.
That is all that is required to configure Monologue to capture all your logged values periodically, publish them to NetworkTables, and add them to the on-robot data logging. Next, let's set up some values to log.
Monologue offers two annotations (@Log.NT
, @Log.File
), which can be applied to variables of supported types, or methods that return the supported types. Note that any method you apply the annotation to will be run every periodic loop. To use these, simply annotate the field or method with the desired annotation. The class containing the annotated field must implement Logged
, even your root container. Once a class has been declared Logged
, Monologue will automatically search it for annotated fields and getters to capture - as long as it is reachable from the specified root through a direct sequence of Logged
parent classes (the logger will recursively search down the tree of all Logged
fields from the root container and place the values in the NT/DataLog tree according to the class structure.).
- Primitives:
int, long, float, double, boolean
- Primitive arrays:
int[], long[], float[], double[], boolean[]
- String and String[] (note that logging Strings is significantly more performance-heavy than logging primitives)
- WPILib struct-serializable types: for example, geometry types (Pose2d, etc), other simple structured data (SwerveModuleState, etc). For the full list of struct-serializable types, see the implementing classes of StructSerializable in WPILib's Javadocs.
- Arrays of the above struct-serializable types.
- Sendables such as Field2d and Mechanism2d. (Note that these will always publish to NetworkTables, and ignore the file-only and lazy-logging features of Monologue. This is due to limitations in the Sendable API.)
Each annotated field can be set up with an optional logging level. These determine how Monologue handles the field based on the global fileOnly
flag.
When used with a @Log.File
annotation, the field will only appear in the datalog, and only while fileOnly
is false.
When used with a @Log.NT
annotation, the field will appear on NetworkTables and in the datalog, but only while fileOnly
is false.
When fileOnly
is true, the field will not be logged at all.
If a level is not specified, this level will be used.
When used with a @Log.File
annotation, the field will appear in the datalog at all times, and will not appear on NetworkTables.
When used with a @Log.NT
annotation, the field will appear in the datalog at all times. Additionally, the field will appear on NetworkTables, only while fileOnly
is false.
When used with a @Log.File
annotation, the field will appear in the datalog at all times, and will not appear on NetworkTables.
When used with a @Log.NT
annotation, the field will appear in the datalog at all times and on NetworkTables at all times, regardless of the value of fileOnly
.
Use OVERRIDE_FILE_ONLY for any values you want to communicate over NetworkTables while
fileOnly
is false. This includes driver dashboards and custom coprocessor communication (though Monologue is not recommended for building NetworkTables communication protocols to coprocessors).
By making a class implement Logged
, you not only mark it for Monologue to include in the logging tree, you also gain access to methods that allow you to one-shot log additional fields to the right place in the logging tree.
To imperatively log an additional value, call this.log(String key, T value, LogLevel level)
. The level
parameter is optional, and Monologue will use LogLevel.DEFAULT
if not specified. The key will be relative to the Logged class's place in the tree. Therefore, if you are in a class that is logged as /Robot/drivetrain
, and call log("error", 2.4)
, an entry will be in the logging tree under /Robot/drivetrain/error
, with a value of 2.4
.
There are three major caveats with this feature.
-
log
calls made beforeMonologue.setupMonologue
is called will be silently dropped. This includes calls made in the constructor of theLogged
class. - Sendables cannot be logged using these calls, but all other data types above are supported.
- Using a key that conflicts with the name of an annotated field or method will likely cause conflicting data recorded in the datalog, and will possibly cause NetworkTables errors. Making
log
calls to the same key from different places in the class will not cause this issue.