examples/errors/ turns three messages into the three ways a program reports trouble.

The message file

# errors.msg — messages that are errors: an exception class with a throw
# function, a fatal error function and a syslog function.

$MODULE errors
$NAMESPACE app :: errors
$LANGUAGE en

# ConfigMissingException derives from std::exception (publicly, the
# default); ThrowConfigMissing( path ) throws it. what() returns the text.
$EXCEPTION INHERITED std::exception
$THROW ENABLE

$MESSAGE ConfigMissing
@ path std::string const &
"configuration file '{$path}' is missing"
[tr]
"yapılandırma dosyası '{$path}' bulunamadı"

# FatalError( code ) prints the text on std::cerr and runs the EXIT statement.
$THROW DISABLE
$ERROR ENABLE
$ERROR EXIT std::exit( 2 )
$ERROR PREFIX Fatal

$MESSAGE Error
@ code int
|fatal error {$code}, giving up
[tr]
|ölümcül hata {$code}, vazgeçiliyor

# LogStarted( pid ) sends the text to syslog, by default as LOG_DAEMON | LOG_NOTICE.
$ERROR DISABLE
$SYSLOG ENABLE
$SYSLOG FACILITY DAEMON
$SYSLOG LEVEL NOTICE

$MESSAGE Started
@ pid long
"started, pid {$pid}"
[tr]
"başladı, süreç {$pid}"

The settings are sticky, so the file reads top to bottom: $THROW is on for ConfigMissing only, $ERROR for Error only, $SYSLOG for Started. $ERROR PREFIX Fatal replaces both of $ERROR's defaults — Error + Error becomes FatalError, not FatalErrorError.

The program

#include "errors.hh"

#include <cstring>
#include <fstream>
#include <iostream>

#include <unistd.h>

namespace
{
  void Load( std::string const &path )
  {
    std::ifstream file( path );

    if ( ! file )
    {
      app::errors::ThrowConfigMissing( path );
    }
  }
}

int main( int argc, char **argv )
{
  // Only when asked: the smoke test does not write to the system log.
  if ( argc > 1 && std::strcmp( argv[1], "--syslog" ) == 0 )
  {
    app::errors::LogStarted( static_cast<long>( getpid( ) ) );
  }

  try
  {
    Load( "/nonexistent/app.conf" );
  }
  catch ( std::exception const &e )
  {
    std::cout << "caught: " << e.what( ) << std::endl;
  }

  app::errors::FatalError( 7 );   // does not return: std::exit( 2 )
}

Output

caught: configuration file '/nonexistent/app.conf' is missing
fatal error 7, giving up

The first line is what() of the exception; the second is FatalError writing to std::cerr before std::exit( 2 ) — the smoke test checks both lines and the exit code 2. LogStarted runs only with --syslog, so the test does not write to the system log.

What was generated

class ConfigMissingException : public std::exception { ... };
[[noreturn]] void ThrowConfigMissing( std::string const & path, std::locale const &loc );
[[noreturn]] void ThrowConfigMissing( std::string const & path );
void FatalError( int code, std::locale const &loc );
void FatalError( int code );
void LogStarted( long pid, std::locale const &loc, int option_parameter = LOG_DAEMON | LOG_NOTICE );
void LogStarted( long pid, int option_parameter = LOG_DAEMON | LOG_NOTICE );