SO 5.8 ByExample Custom Error Logger - Stiffstream/sobjectizer GitHub Wiki

Note. It is better to read SO-5.8 Basics before this text.

Introduction

This examples demonstrates usage of custom error logger with SObjectizer Environment. The example also uses message limits to provoke an error. There is no need to understand how message limits work, but more information about message limits can be found here: SO-5.8 InDepth Message Limits

Some Words About Error Logger

Until v.5.5.0 SObjectizer was based on ACE Framework. SObjectizer used some features from ACE and one of them was ACE_Logging facility. When some error happened inside SObjectizer core then ACE_Logging macros (like ACE_ERROR) were used to log error message. User can customize error logging process by tuning ACE_Logging. For example ACE_Logging may be set to store error message to some file or to Event Log on Windows or to syslog on Unix.

Since v.5.5.0 SObjectizer no more uses ACE Framework. It means that ACE_Logging is not available inside SObjectizer core. And if some error occurs then SObjectizer uses std::cerr as a stream for error logging. For some users and applications this can be inappropriate. In such cases user must use its own error_logger_t interface implementation. This example shows basic idea how it can be done.

What Example Does

The sample implements so_5::error_logger_t interface. It installs an instance of that implementation as an error logger for SObjectizer Environment.

To provoke SObjectizer to use the error logger an incorrect message limit reaction is used: a message is redirected to the same mbox over and over again. SObjectizer detects such a redirection and treats it as a non-fatal error. A message about this case is logged, but the application continues to work, ignoring the problematic message. The user's error logger is used to log the message about the error.

Sample Code

#include <iostream>
#include <stdexcept>

// Main SObjectizer header file.
#include <so_5/all.hpp>

// A class that uses limit_then_redirect incorrectly.
// Message is redirected too many times and this lead to error message.
class actor_t final : public so_5::agent_t
{
	struct hello final : public so_5::signal_t {};
	struct bye final : public so_5::signal_t {};

public :
	actor_t( context_t ctx )
		:	so_5::agent_t{ ctx
				// There is a mistake: message is redirected to the same mbox.
				+ limit_then_redirect< hello >(
						1, [this]{ return so_direct_mbox(); } )
				+ limit_then_abort< bye >( 1 ) }
	{}

	void so_define_agent() override
	{
		so_subscribe_self()
			.event( []( mhood_t<hello> ) { std::cout << "Hello!" << std::endl; } )
			.event( [this]( mhood_t<bye> ) { so_deregister_agent_coop_normally(); } );
	}

	void so_evt_start() override
	{
		so_5::send< hello >( *this );
		so_5::send< hello >( *this ); // This message will be redirected.
		so_5::send< bye >( *this );
	}
};

// Custom error logger.
class custom_logger_t final : public so_5::error_logger_t
{
public :
	custom_logger_t()
	{}

	void log(
		const char * file_name,
		unsigned int line,
		const std::string & message ) override
	{
		std::clog
			<< "############################################################\n"
			<< file_name << "(" << line << "): error: "
			<< message << "\n"
				"############################################################"
			<< std::endl;
	}
};

int main()
{
	try
	{
		so_5::launch(
			// The SObjectizer Environment initialization.
			[]( so_5::environment_t & env )
			{
				// Creating and registering a cooperation.
				env.register_agent_as_coop( env.make_agent< actor_t >() );
			},
			// Parameters for SObjectizer Environment.
			[]( so_5::environment_params_t & params )
			{
				params.error_logger(
					std::make_shared< custom_logger_t >() );
			} );
	}
	catch( const std::exception & ex )
	{
		std::cerr << "Error: " << ex.what() << std::endl;
		return 1;
	}

	return 0;
}

Sample in Details

Custom Error Logger

Custom error logger is implemented as class custom_logger_t in the sample code:

// Custom error logger.
class custom_logger_t final : public so_5::error_logger_t
{
public :
	custom_logger_t()
	{}

	void log(
		const char * file_name,
		unsigned int line,
		const std::string & message ) override
	{
		std::clog
			<< "############################################################\n"
			<< file_name << "(" << line << "): error: "
			<< message << "\n"
				"############################################################"
			<< std::endl;
	}
};

It is a very simple implementation. The base interface, so_5::error_logger_t has just one pure virtual method -- log(). This method must be reimplemented in descendant classes and custom_logger_t does just that.

The log() method has three parameters:

  • file_name. This is the name of SObjectizer's source file where the error has been detected;
  • line. This is line number inside SObjectizer's source file where the error has been detected;
  • message. This is text of error message formed by SObjectizer itself.

It is important to note that file_name and line show the place inside SObjectizer's code where the error has been detected. Not the place in the user's code where error has been produced.

Installing Error Logger into SObjectizer Environment

The custom error logger is installed into SObjectizer Environment during Environment's parameters tuning phase in so_5::launch() functions:

so_5::launch(
	// The SObjectizer Environment initialization.
	[]( so_5::environment_t & env )
	{
            ...
	},
	// Parameters for SObjectizer Environment.
	[]( so_5::environment_params_t & params )
	{
		params.error_logger(
			std::make_shared< custom_logger_t >() );
	} );

An error logger object must be created as dynamically allocated object and must be passed to SObjectizer Environment's parameters as std::shared_ptr wrapper. The name so_5::error_logger_shptr_t is just a useful synonym for std::shared_ptr<so_5::error_logger_t>.

⚠️ **GitHub.com Fallback** ⚠️