Logging frameworks

The Badlog post has prompted me to ask about logging frameworks generally. We want to implement a proper logging framework this season - we certainly suffered from not having one last season.

Badlog looks very good, and we will definitely have a play with it. However, our team is fairly new, and I wonder if there are other frameworks around that we can compare to.

So the question is: are there other frameworks that are recommended as well?

Shuffleboard saves all the values it sees to disk and lets you play back the recorded data in the dashboard or export it to a CSV file. Pretty much every physical thing on the robot (sensors, motor controllers, subsystems, etc) are already logged in WPILib via the LiveWindow. Custom information can be sent over NetworkTables through the SmartDashboard class, the Shuffleboard class (new in 2019), or manually with the NetworkTables API.

Thanks Sam

I note that Shuffleboard requires JDK 11. Couple of questions:

  1. We have been using JDK 8 with VS Code, quite successfully. Are there any issues with upgrading to JDK 11?

  2. Oracle have substantially changed the licensing with JDK 11. Are teams using the Oracle download, or the GPL release on jdk.java.net?

Regards

David

I believe the installer for the 2019 season will use the OpenJDK.

  1. Not for teams, no. The JDK used for FRC programming is comes bundled with the WPILib installer. VS Code will use that JDK for FRC projects, but it will not be on the PATH, so your system environment variables will be unchanged. The tool launchers in VS Code will use that JDK for running Shuffleboard and the other Java desktop tools.

  2. Teams will be using OpenJDK

Thanks Prateek and Sam

Is there a preview for this 2019 shuffleboard available yet? we had a poor experience with shuffleboard last year, but are extremely excited for the potential that we saw. I would love to start evaluating it.

By the way, the vs code and Gradle set up that was published in the alpha is absolutely fantastic.

Everything is on GitHub and the Maven repo is public, so you can grab the beta Shuffleboard now. You will need Java 11 to run the 2019 beta version though.

If you weren’t using the latest 2018 version of Shuffleboard (v1.3.1) though, it’ll probably be easier to grab that first, as there were a few bugfixes and minor improvements after the last WPILib 2018 release: Release v1.3.1: Fix null pointers in sendable chooser stuff (#449) · wpilibsuite/shuffleboard · GitHub

Depends on what you want to accomplish by logging.

If you are just looking for code debug, something like slf4j’s simplelogger may be enough.

If you are looking to do something more like logged robot telemetry, you are going to need a different solution such as badlog.

Let me speak up in favor of simple debug logging. All robot programmers should be putting some well chosen print statements into their code. The results will show up on your driver’s console and will also be viewable for all previous matches on the driver station Log Viewer. This can provide critical information such as which commands really executed, what your vision system was seeing, or how much air pressure you had available.

Simple print statements will do the job. If you want a slightly more sophisticated logging framework, I suggest the java.util.logging framework. It is built into your JVM, so you won’t need to add any dependencies to your build.gradle file.

I have some notes on configuring JUL loggers at: https://firstmncsa.org/2018/12/09/debugging-print-statements-and-logging/

1 Like

Thanks very much Keith. I am very familiar with logging - use log4net and Serilog extensively, and various others in professional life.

I agree that a lot can be done with simple print statements, but that gets very hard to manage very quickly.

The advantage of Badlog and Shuffleboard is they incorporate stuff for the physical environment we find ourselves. I am slightly concerned that Badlog might be a bit sophisticated for our team at the moment, but I have not spent enough time with it yet.

Your blog post on java.util.logging is very good, and we may well start with that.

Regards

David

Hi Dave,

What did you end up doing with your logging? I’m desperately trying to find some way of improving our logging. I’ve read many threads here about it, have looked into Shuffleboard’s NetworkTables view, etc. Seems like many revolve around printing out diagnostics to a file, then downloading it. I’m not even interested in that yet; I’ve learned all that telemetry is already available somewhere in the background; WPILIB can dump it, or Shufffleboard can record it and output it, etc.

All I’m interested in right now is just seeing OUR simple string messages, uncluttered by all the stuff wpilib and roborio prints out itself. I was hoping Shuffleboard could do that with the NetworkTables, but after looking into that, it looks like that’s not a great use case for a history of messages.

Hi @codeman73

Sorry for delay in response. We are actually using java.util.logging (JUL) with some wrapper classes to make it a little more hospitable. Currently just logging to the console, and not getting too much output from the WPI stuff to interfere.

Actually getting it going was slightly tricky. You can see our code on GitHub:

We are using a logging.properties file for setup, and put it into the project deploy directory so that it gets sent to the RoboRio. Note how it is set up in robotInit().

The format for the log line is set in the properties file. The one we are using gives timing to the millisecond, the log level and the message.

The wrapper class is there to make generating a log message a little easier. Basic JUL logging has a slightly odd setup, and does not support using java String.format() style messages, so the wrapper classes allow that, and make it easier to log exceptions. They also make the log messages conform to SLF4J format, so if we switch to a more advanced logging framework at some point, should not have any impact.

The PeriodicLogger class is there to make it a bit easier to have log messages in the periodic loops (e.g teleopInit()) and not get overwhelmed. It only logs every Nth call - so if you construct with say 50 as the N value, it only logs every 50th call - which equates to one per second in teleopPeriodic.

Hope that helps. let me know if you have any questions.

David

Hi Dave, thanks for all that. So does your logger write out to a separate file?
If so, how do you get that file off the rio and where you can see it?

We do not have it writing to a file yet. Planning to write to a USB stick - as soon as we have done that, will post back here.

Do you have an example of your logging.properties file?

Here are the contents. You can also check out GitHub here:


handlers = java.util.logging.ConsoleHandler
.level = ALL

Arguments to the format string are used to produce a string from a LogRecord:

1 - date - a Date object representing event time of the log record

2 - source - a string representing the caller, if available; otherwise, the logger’s name.

3 - logger - the logger’s name

4 - level - the log level

5 - message - the formatted log message returned from the Formatter.formatMessage(LogRecord) method.

It uses java.text formatting and does NOT use the java.util.Formatter format argument

To provide params to the message, need to use the method:

log(Level level, String msg, Object[] params)

the msg string would for format parameters in the format: { ArgumentIndex , FormatType , FormatStyle }

e.g. log(“At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.”, new object[] {planet, new Date(), event}))

see: https://docs.oracle.com/javase/7/docs/api/java/text/MessageFormat.html

6 - thrown - a string representing the throwable associated with the log record and its backtrace

beginning with a newline character, if any; otherwise, an empty string

java.util.logging.SimpleFormatter.format=[%1$tm-%1$td %1$tT:%1$tL] [%4$-7s] %5$s %n

java.util.logging.ConsoleHandler.level=ALL
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

frc.robot.handlers=java.util.logging.ConsoleHandler

Looks like Discus format interprets a ‘#’ as a command to bold everything. The bold lines start with a ‘#’ which indicates a comment in the file.

Alos, our wrapper class avoids the necessity to use the MessgeFormat - we use String.format instead

If you put three backticks (```) on a line before and after, it’ll format everything in between as a code block, like so:

# This is fine

Discus uses markdown to format comments - here’s a nifty cheatsheet for future reference

Cool - thanks