firmware-base/lib/ArduinoLog/ArduinoLog.h

385 lines
9.7 KiB
C++

/*
_ ___ ___ _ _ ___ _ _ ___ _ ___ ___
/_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __|
/ _ \| / |) | |_| || || .` | (_) | |_| (_) | (_ |
/_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___|
Log library for Arduino
version 1.1.1
https://github.com/thijse/Arduino-Log
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
*/
#pragma once
#include <inttypes.h>
#include <stdarg.h>
// Non standard: Arduino.h also chosen if ARDUINO is not defined. To facilitate use in non-Arduino test environments
#if ARDUINO < 100
#include "WProgram.h"
#else
#include "Arduino.h"
#endif
// PGM stubs to facilitate use in non-Arduino test environments
#ifndef PGM_P
#define PGM_P const char *
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#define PSTR(str) (str)
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
#endif
typedef void (*printfunction)(Print*, int);
// *************************************************************************
// Uncomment line below to fully disable logging, and reduce project size
// ************************************************************************
//#define DISABLE_LOGGING
#define LOG_LEVEL_SILENT 0
#define LOG_LEVEL_FATAL 1
#define LOG_LEVEL_ERROR 2
#define LOG_LEVEL_WARNING 3
#define LOG_LEVEL_INFO 4
#define LOG_LEVEL_NOTICE 4
#define LOG_LEVEL_TRACE 5
#define LOG_LEVEL_VERBOSE 6
#define CR "\n"
#define LF "\r"
#define NL "\n\r"
#define LOGGING_VERSION 1_0_4
/**
* ArduinoLog is a minimalistic framework to help the programmer output log statements to an output of choice,
* fashioned after extensive logging libraries such as log4cpp ,log4j and log4net. In case of problems with an
* application, it is helpful to enable logging so that the problem can be located. ArduinoLog is designed so
* that log statements can remain in the code with minimal performance cost. In order to facilitate this the
* loglevel can be adjusted, and (if your code is completely tested) all logging code can be compiled out.
*
* ---- Wildcards
*
* %s display as string (char*)
* %S display as string from flash memory (__FlashStringHelper* or char[] PROGMEM)
* %c display as single character
* %C display as single character or as hexadecimal value (prefixed by `0x`) if not a printable character
* %d display as integer value
* %l display as long value
* %u display as unsigned long value
* %x display as hexadecimal value
* %X display as hexadecimal value prefixed by `0x` and leading zeros
* %b display as binary number
* %B display as binary number, prefixed by `0b`
* %t display as boolean value "t" or "f"
* %T display as boolean value "true" or "false"
* %D,%F display as double value
* %p display a printable object
*
* ---- Loglevels
*
* 0 - LOG_LEVEL_SILENT no output
* 1 - LOG_LEVEL_FATAL fatal errors
* 2 - LOG_LEVEL_ERROR all errors
* 3 - LOG_LEVEL_WARNING errors and warnings
* 4 - LOG_LEVEL_INFO errors, warnings and notices
* 4 - LOG_LEVEL_NOTICE Same as INFO, kept for backward compatibility
* 5 - LOG_LEVEL_TRACE errors, warnings, notices, traces
* 6 - LOG_LEVEL_VERBOSE all
*/
class Logging
{
public:
/**
* default Constructor
*/
Logging()
#ifndef DISABLE_LOGGING
: _level(LOG_LEVEL_SILENT),
_showLevel(true),
_logOutput(NULL)
#endif
{
}
/**
* Initializing, must be called as first. Note that if you use
* this variant of Init, you need to initialize the baud rate
* yourself, if printer happens to be a serial port.
*
* \param level - logging levels <= this will be logged.
* \param printer - place that logging output will be sent to.
* \return void
*
*/
void begin(int level, Print *output, bool showLevel = true);
/**
* Set the log level.
*
* \param level - The new log level.
* \return void
*/
void setLevel(int level);
/**
* Get the log level.
*
* \return The current log level.
*/
int getLevel() const;
/**
* Set whether to show the log level.
*
* \param showLevel - true if the log level should be shown for each log
* false otherwise.
* \return void
*/
void setShowLevel(bool showLevel);
/**
* Get whether the log level is shown during logging
*
* \return true if the log level is be shown for each log
* false otherwise.
*/
bool getShowLevel() const;
/**
* Sets a function to be called before each log command.
*
* \param f - The function to be called
* \return void
*/
void setPrefix(printfunction f);
/**
* clears prefix.
*
* \return void
*/
void clearPrefix();
/**
* Sets a function to be called after each log command.
*
* \param f - The function to be called
* \return void
*/
void setSuffix(printfunction f);
/**
* clears suffix.
*
* \return void
*/
void clearSuffix();
/**
* Output a fatal error message. Output message contains
* F: followed by original message
* Fatal error messages are printed out at
* loglevels >= LOG_LEVEL_FATAL
*
* \param msg format string to output
* \param ... any number of variables
* \return void
*/
template <class T, typename... Args> void fatal(T msg, Args... args){
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_FATAL, false, msg, args...);
#endif
}
template <class T, typename... Args> void fatalln(T msg, Args... args){
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_FATAL, true, msg, args...);
#endif
}
/**
* Output an error message. Output message contains
* E: followed by original message
* Error messages are printed out at
* loglevels >= LOG_LEVEL_ERROR
*
* \param msg format string to output
* \param ... any number of variables
* \return void
*/
template <class T, typename... Args> void error(T msg, Args... args){
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_ERROR, false, msg, args...);
#endif
}
template <class T, typename... Args> void errorln(T msg, Args... args){
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_ERROR, true, msg, args...);
#endif
}
/**
* Output a warning message. Output message contains
* W: followed by original message
* Warning messages are printed out at
* loglevels >= LOG_LEVEL_WARNING
*
* \param msg format string to output
* \param ... any number of variables
* \return void
*/
template <class T, typename... Args> void warning(T msg, Args...args){
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_WARNING, false, msg, args...);
#endif
}
template <class T, typename... Args> void warningln(T msg, Args...args){
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_WARNING, true, msg, args...);
#endif
}
/**
* Output a notice message. Output message contains
* N: followed by original message
* Notice messages are printed out at
* loglevels >= LOG_LEVEL_NOTICE
*
* \param msg format string to output
* \param ... any number of variables
* \return void
*/
template <class T, typename... Args> void notice(T msg, Args...args){
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_NOTICE, false, msg, args...);
#endif
}
template <class T, typename... Args> void noticeln(T msg, Args...args){
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_NOTICE, true, msg, args...);
#endif
}
template <class T, typename... Args> void info(T msg, Args...args) {
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_INFO, false, msg, args...);
#endif
}
template <class T, typename... Args> void infoln(T msg, Args...args) {
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_INFO, true, msg, args...);
#endif
}
/**
* Output a trace message. Output message contains
* N: followed by original message
* Trace messages are printed out at
* loglevels >= LOG_LEVEL_TRACE
*
* \param msg format string to output
* \param ... any number of variables
* \return void
*/
template <class T, typename... Args> void trace(T msg, Args... args){
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_TRACE, false, msg, args...);
#endif
}
template <class T, typename... Args> void traceln(T msg, Args... args){
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_TRACE, true, msg, args...);
#endif
}
/**
* Output a verbose message. Output message contains
* V: followed by original message
* Debug messages are printed out at
* loglevels >= LOG_LEVEL_VERBOSE
*
* \param msg format string to output
* \param ... any number of variables
* \return void
*/
template <class T, typename... Args> void verbose(T msg, Args... args){
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_VERBOSE, false, msg, args...);
#endif
}
template <class T, typename... Args> void verboseln(T msg, Args... args){
#ifndef DISABLE_LOGGING
printLevel(LOG_LEVEL_VERBOSE, true, msg, args...);
#endif
}
private:
void print(const char *format, va_list args);
void print(const __FlashStringHelper *format, va_list args);
void print(const Printable& obj, va_list args)
{
_logOutput->print(obj);
}
void printFormat(const char format, va_list *args);
template <class T> void printLevel(int level, bool cr, T msg, ...)
{
#ifndef DISABLE_LOGGING
if (level > _level)
{
return;
}
if (level < LOG_LEVEL_SILENT)
{
level = LOG_LEVEL_SILENT;
}
if (_prefix != NULL)
{
_prefix(_logOutput, level);
}
if (_showLevel) {
static const char levels[] = "FEWITV";
_logOutput->print(levels[level - 1]);
_logOutput->print(": ");
}
va_list args;
va_start(args, msg);
print(msg, args);
if(_suffix != NULL)
{
_suffix(_logOutput, level);
}
if (cr)
{
_logOutput->print(CR);
}
#endif
}
#ifndef DISABLE_LOGGING
int _level;
bool _showLevel;
Print* _logOutput;
printfunction _prefix = NULL;
printfunction _suffix = NULL;
#endif
};
extern Logging Log;