Jump to content

Programming: logging


Sensei

Recommended Posts

When programming, logging is an essential operation to find out what happened and why it happened. Especially in an application written on Linux and running on a server, without a GUI, whose output goes to a terminal / shell.

 

I have created some basic C++ classes that can be useful in an application (C++, but they can be easily adapted to other OOP languages).

 

Logs.Base is a virtual class without implemented methods.

Logs.QuietLogs is implemented as a no-op. Simply put, nothing, quiet.

Logs.Logs is implemented to write only about serious errors (Logs.Error() method implemented).

Logs.VerboseLogs is implemented to write about errors and warnings (Logs.Warning() method implemented).

Logs.VeryVerboseLogs is implemented to write about errors, warnings and notifications (Logs.Notice() method implemented).

 

By passing a generic logging class object to functions, methods, classes, constructors, etc., they can write what they want to the logging object, but what appears to the user depends on user willingness to listen using -q (--quiet), -s (--silent), -v (--verbose), -vv (--very-verbose) etc. on the command line..

 

Writing to a separate log file can be as simple as creating another Logs.Base subclass with the appropriate methods overridden, or even over the network.

 

// Logs v1.0 (c) 2023 Sensei (aka 'Q') (8.XI.2023)

#include <iostream>

namespace Logs {
	class Base {
		public:
			virtual void Notice( const std::string &message ) = 0;
			virtual void Warning( const std::string &message ) = 0;
			virtual void Error( const std::string &message ) = 0;
	};

	class QuietLogs : public Base {
		public:
			virtual void Notice( const std::string &message ) {}
			virtual void Warning( const std::string &message ) {}
			virtual void Error( const std::string &message ) {}
	};

	class Logs : public QuietLogs {
		public:
			virtual void Error( const std::string &message ) {
				std::cerr << message << std::endl;
			}
	};

	class VerboseLogs : public Logs {
		public:
			virtual void Warning( const std::string &message ) {
				std::cerr << message << std::endl;
			}
	};

	class VeryVerboseLogs : public VerboseLogs {
		public:
			virtual void Notice( const std::string &message ) {
				std::cout << message << std::endl;
			}
	};
};

class Program {
	public:
		Program( const std::string &title, Logs::Base &logs ) {
			std::cout << "Testing " << title << std::endl;
			logs.Error( "Error!" );
			logs.Warning( "Warning!" );
			logs.Notice( "Notice!" );
			std::cout << std::endl;
		}
};

int main( int argc, const char *argv[] ) {
	Logs::VeryVerboseLogs l3;
	Program p1( "Very Verbose Logs Test", l3 );

	Logs::VerboseLogs l2;
	Program p2( "Verbose Logs Test", l2 );

	Logs::Logs l1;
	Program p3( "Logs Test", l1 );

	Logs::QuietLogs l0;
	Program p4( "Quiet Test", l0 );

	return( 0 );
}

 

Example output:

 

./logs              
Testing Very Verbose Logs Test
Error!
Warning!
Notice!

Testing Verbose Logs Test
Error!
Warning!

Testing Logs Test
Error!

Testing Quiet Test

 

I think passing arguments --verbose, --very-verbose, --quiet, --silent, etc. is quite sloppy in code.. better instead to create such a C++ class..

 

logs.cpp

Edited by Sensei
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.