Tutorial: Logging with system 6.0+ (loop and libs/custom classes)

This is a touch early but I am pretty excited about the new Logging feature and what it can do for users and lib maintainers. I will be updating the DS18B20 to take advantage of the Logging feature so that users can opt in to whatever level of info they choose. In working on that I learned (after opening a GitHub issue that was my own lack of knowledge, thanks @jvanier for setting me straight) how to use the logging feature from inside a lib/custom class. So the Particle crew doesn’t have to repeat themselves the below is a simple example of how to use the Logging/Logger feature in your own apps.

Loop/Main - Whatever you want to call it. This is simple example that outputs “Logged in loop.” and “Log from Custom Class” every 30 seconds. What to take note of here is that Log is a default Logger instance tied to the “app” category. In order to use Log you will need to create a logHandler as such SerialLogHandler logHandler; as of today there is only a SerialLogHandler but I hope that Particle will see fit to create a “Cloud” log handler as a bit of a shortcut to Publish…hint, hint. In the example below you can see three Log Levels being set: LOG_LEVEL_WARN applies to non-application messages (I assume system firmware), app, LOG_LEVEL_TRACE (this is the default Log instance with category app) applies to code within your ino and app.custom LOG_LEVEL_TRACE in this instance applies to the Custom lib/class category. You can see how the Logger myLog instance from Custom.cpp “hooks” into this statement.

// This #include statement was automatically added by the Particle IDE.
#include "Custom.h"
#include "application.h"

#define LOGGING_ON TRUE

#if (LOGGING_ON) 
    SerialLogHandler logHandler(LOG_LEVEL_WARN, {
        { "app", LOG_LEVEL_TRACE },
        { "app.custom", LOG_LEVEL_TRACE }
    });
#endif

Custom myObj;
const int myLog_tempo = 30000;
int next_log;

void setup() {
  Log.trace("Logging Enabled, moving to Loop");

}

void loop() {
  if (millis() > next_log){
    Log.info("Logged in loop.");
    myObj.some_function();
    next_log = millis() + myLog_tempo;
    }
}

Custom.cpp - Only the CPP really matters for this tutorial as that is where you should instantiate a Logger instance for a given class/lib. This is where I went wrong in trying to use the Logging feature. You can also place the static keyword in front of Logger myLog("app.whatever"); in order to reuse myLog in other CPP files.

#include "Custom.h"
Logger myLog("app.custom");

Custom::Custom() {

}

Custom::~Custom() {

}

void Custom::some_function(){
  myLog.info("Log from custom class.");
}

As you can see above I use the myLog Logger instance to send a log message that is “tagged” as being an info level log. If you remember above myLog is associated with the app.custom category so the output from calling the some_function(); function would be as follows:
0000000044 [app.custom] INFO: Log from custom class.

Custom.h - Has no bearing on Logging.

#include "application.h"

#ifndef Custom_h
#define Custom_h

class Custom {
private:
    
public:
    Custom();
    ~Custom();
    void some_function();
};

#endif /* Custom_h */

Using the info from above you should be able to add custom logging categories and loggers to your favorite libs and classes. Go forth and destroy those Serial.print statements!!!

8 Likes

Hi @LukeUSMC thank you for all your tutorials, I also used the one about JSON data and It was really helpful.
Now I see that this is new in the firmware release, but, I don’t understand this about Logs… What are they? Where you can use it? I see that you mentioned to destroy all the Serial.print statements, so, Where you can see this logs? I’m new in this stuff :sweat_smile:
Thank you!

1 Like

For now Logs are a local only Serial output that allows you to insert messages to yourself or your users (of say a library) that are “tagged” into categories and severity. Just open your Serial Terminal of choice, connect to your Photon and you should see your logged events output there. The severity levels are not all that dissimilar to Windows Event Logs, if you have a Windows PC check your event logs and you will get an idea of they decide what belongs at what level. You can recreate all of the functionality of Logging using Serial.println, lots of DEFINES and IF statements but using Logging gives a common interface for all of us. Best way to learn is to throw 6.0 on a Photon and follow some of the examples in the Reference section of the docs. https://docs.particle.io/reference/firmware/photon/#logging

1 Like

Not quite.
There is a member contributed library available on Particle Build that should allow UDP loggin too

Oh, now I understand, well I’ll begin practice with this new stuff, thank you so much!