Appender with multi-class example for logging system - c++

I'm newbie working with a logging system, but it's something very useful to add to your programs.
Summarizing my problem. I use the logging library log4cplus
I doing and easy example with two simple classes and the main program.
That's my error log:
log4cplus:ERROR No appenders could be found for logger (main).
log4cplus:ERROR Please initialize the log4cplus system properly.
Segmentation fault: 11
The problem is i don't know how to solve the problem with the appender.
That's basic code of my example.
Class1.h
#include <iostream>
#include <log4cplus/configurator.h>
#include <log4cplus/logger.h>
using namespace std;
// Use the log4cplus namespace
using namespace log4cplus;
class one
{
private:
// Create the logger
Logger logger;
public:
bool flag;
int valor;
one();
int multiplica(int a);
};
Class1.cpp
one::one()
{
logger.getInstance(LOG4CPLUS_TEXT("Clase One - constructor."));
}
int one::multiplica(int a)
{
int sol = 0;
sol = valor * a;
// Imprimo un mesaje en el log.
LOG4CPLUS_INFO(logger, "El resultado de la multiplicación es: xx");
return sol;
}
Class2.h
#include <iostream>
#include <log4cplus/configurator.h>
#include <log4cplus/logger.h>
using namespace std;
// Use the log4cplus namespace
using namespace log4cplus;
class two
{
private:
// Create the logger
Logger logger;
public:
bool flag;
int valor;
two();
int suma(int a);
};
Class.cpp
two::two()
{
logger.getInstance(LOG4CPLUS_TEXT("Clase Two - DEconstructor."));
}
int two::suma(int a)
{
int sol = 0;
sol = valor + a;
// Imprimo un mesaje en el log.
LOG4CPLUS_INFO(logger, "El resultado de la suma es: YY ");
return sol;
}
main.cpp
int main(int argc, char** argv)
{
// Load the properties
PropertyConfigurator::doConfigure("logClase.properties");
Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("main"));
// Log with INFO level
if (logger.isEnabledFor(INFO_LOG_LEVEL))
{
LOG4CPLUS_INFO(logger, "Application startup");
}
one uno;
two dos;
uno.valor = dos.valor = 4;
uno.multiplica(7);
dos.suma(7);
// Log with INFO level
if (logger.isEnabledFor(INFO_LOG_LEVEL))
{
LOG4CPLUS_INFO(logger, "Application shutdown");
}
return 0;
}
What i'm doing wrong ???
That's the correct way to work with the logging system ??
I use a simple properties file to save all the log messages in a file.
That's my logClase.properties file to configure de logger.
log4cplus.rootLogger=INFO, STDOUT, FILEAPPENDER
log4cplus.logger.main=INFO
log4cplus.logger.utils=FILEAPPENDER
log4cplus.appender.STDOUT=log4cplus::ConsoleAppender
log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout
log4cplus.appender.STDOUT.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S} [%t] %-5p %c{2} %%%x%% - %m [%l]%n
log4cplus.appender.FILEAPPENDER=log4cplus::RollingFileAppender
log4cplus.appender.FILEAPPENDER.File=KlasseEx.log
log4cplus.appender.FILEAPPENDER.MaxFileSize=5MB
#log4cplus.appender.FILEAPPENDER.MaxFileSize=500KB
log4cplus.appender.FILEAPPENDER.MaxBackupIndex=1
log4cplus.appender.FILEAPPENDER.layout=log4cplus::PatternLayout
log4cplus.appender.FILEAPPENDER.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S} [%t] %-5p %c{2} %%%x%% - %m [%l]%n
I want to use FILEAPPENDER and the Console appender to throw messages in a file and into the console. I think that's not must be so difficult to do, it must be easy to do it.

See for appenders in log4cplus documentation. You probably missing some step of intialitation of this logger - I mean you did not add appenders.
See http://www.codeproject.com/Articles/15955/logging-made-easy-in-your-c-applications
After:
Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("main"));
Missing:
SharedAppenderPtr consoleAppender(new ConsoleAppender());
consoleAppender->setName("myAppenderName");
consoleAppender->setLayout(new log4cplus::TTCCLayout());
logger.addAppender(consoleAppender);

PiotrNycz mentioned that you indeed needed to do more initialization steps for your log4cplus logging, particularly adding appenders. I want to elaborate more on that.
Documentation states that prior to version 2.0 initialization is to be done with:
log4cplus::initialize();
and deinitialization, by calling shutdown() on the Logger like so:
log4cplus::Logger::getRoot().shutdown();
, while after version 2.0, initialization is supposed to occur with instantiating the RAII class log4cplus::Initializer initializer; and deinitialization when that instance is destructed.
However I have version 2.0.0 and the prior method is what actually has worked for me. With the 2nd method I was getting the exact same error you did.
Then a minimal implementation of logging for a class could be like so:
const wchar_t* PATTERN = LOG_PATTERN; // optional - create an initial log status message
log4cplus::SharedAppenderPtr consoleApp(new log4cplus::ConsoleAppender()); // for console output
consoleApp->setLayout(std::unique_ptr<log4cplus::Layout>(new log4cplus::PatternLayout(PATTERN))); // again optional
log4cplus::Logger m_logger = log4cplus::Logger::getRoot(); // get root logger
m_logger.setLogLevel(log4cplus::ALL_LOG_LEVEL); // set root logger log level
// finally add appenders
this->m_logger.addAppender(consoleApp); // at least one appender must be set in order for you to be able to actually log to the console or file or to an output device (multiple appender types exist).
Now, a custom MyLogger class should minimally contain a log4cplus::Logger, logging functions - like the following logError - and the initialization steps mentioned above done in its constructor. Also, it needs a member function GetLogger defined as such: log4cplus::Logger* GetLogger(const char* logger = DEFAULT_LOGGER); to acquire a MyLogger instance and use it as a member of a class for which you want to provide the logging facilities.
To log a specific message you also need a function like this in MyLogger:
template<typename... Args>
inline void logError(const char* stringOptionallyFormatted, Args&&... args)
{
LOG4CPLUS_ERROR_FMT(m_logger, fmt, std::forward<Args>(args)...);
}
(Likewise for other log levels.)
Now instantiate a logger instance in some class's constructor (or in main):
MyLogger myLoggerInstance;
myLoggerInstance.GetLogger(L"File System Logger");
and log with:
myLoggerInstance.logError|Info|Debug("like today is %s No%d", "Sunday", 7 );
or:
logger.logDebug(L"no formatted string");
Additional notes:
I have found documenetation for log4cplus to be relatively poor. This (which is for log4j! - the java original) tutorial is the best one I have found. It explains the basics very well. Then the page I linked above as well.
Make sure you call log4cplus::initialize() first thing in main to prevent SIOF.
Typically you want one Logger member object per class you're interested in.
If you're working on a multithreaded application call log4cplus::threadCleanup(); as an additional de-initialization step after calling shutdown.
Only a trivial hello world app link wouldn't need an appender.

Related

Debug Assertion Failed Expression __acrt_first_block == header

I have been trying to figure out why this is happening and maybe it is just due to inexperience at this point but could really use some help.
When I run my code, which is compiled into a DLL using C++20, I get that a debug assertion has failed with the expression being __acrt_first_block == header.
I narrowed down where the code is failing, but the weird part is that it runs just fine when I change the Init(std::string filePath function signature to not contain the parameter. The code is below and hope someone can help.
Logger.h
#pragma once
#include "../Core.h"
#include <memory>
#include <string>
#include "spdlog/spdlog.h"
namespace Ruby
{
class RUBY_API Logger
{
public:
static void Init(std::string filePath);
inline static std::shared_ptr<spdlog::logger>& GetCoreLogger() { return coreLogger; }
inline static std::shared_ptr<spdlog::logger>& GetClientLogger() { return clientLogger; }
private:
static std::shared_ptr<spdlog::logger> coreLogger;
static std::shared_ptr<spdlog::logger> clientLogger;
};
}
Logger.cpp
namespace Ruby
{
std::shared_ptr<spdlog::logger> Logger::coreLogger;
std::shared_ptr<spdlog::logger> Logger::clientLogger;
void Logger::Init(std::string filePath)
{
std::string pattern{ "%^[%r][%n][%l]: %v%$" };
auto fileSink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filePath, true);
// Setup the console and file sinks
std::vector<spdlog::sink_ptr> coreSinks;
coreSinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
coreSinks.push_back(fileSink);
// Bind the sinks to the core logger.
coreLogger = std::make_shared<spdlog::logger>("RUBY", begin(coreSinks), end(coreSinks));
// Set the Patterns for the sinks
coreLogger->sinks()[0]->set_pattern(pattern);
coreLogger->sinks()[1]->set_pattern(pattern);
// Tell spdlog to flush the file loggers on trace or worse message (can be changed if necessary).
coreLogger->flush_on(spdlog::level::trace);
// Set the default level of the logger
coreLogger->set_level(spdlog::level::trace);
// Do the same for the client logger
std::vector<spdlog::sink_ptr> clientSinks;
clientSinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
clientSinks.push_back(fileSink);
clientLogger = std::make_shared<spdlog::logger>("APP", begin(clientSinks), end(clientSinks));
clientLogger->sinks()[0]->set_pattern(pattern);
clientLogger->sinks()[1]->set_pattern(pattern);
clientLogger->flush_on(spdlog::level::trace);
clientLogger->set_level(spdlog::level::trace);
}
}
Entrypoint.h
#pragma once
#ifdef RB_PLATFORM_WINDOWS
extern Ruby::Application* Ruby::CreateApplication();
int main(int argc, char** argv)
{
Ruby::Logger::Init("../Logs/Recent_Run.txt");
RB_CORE_INFO("Initialized the logger.");
auto app = Ruby::CreateApplication();
app->Run();
delete app;
return 0;
}
#else
#error Ruby only supports windows
#endif // RB_PLATFORM_WINDOWS
For anyone else who runs into a similar problem, here is how I fixed it.
Essentially the function signature for the Init() function was the problem. The std::string parameter was causing the debug assertion to fire, my best guess as of right now was because of move semantics but that part I am still not sure on. So there are a couple of ways that I found to fix this.
Method 1:
Make the parameter a const char*. I don't quite like this approach as it then relies on C style strings and if you are trying to write a program in modern C++, this is a huge step backwards.
Method 2:
Make the parameter a const std::string&. Making it a const reference to a string prevents the move semantics (again as far as I know) and the assertion no longer fires. I prefer this fix as it keeps the program in modern C++.
I hope this helps anyone who has similar issues, and be careful with statics and move semantics.

Gtkmm3: Handling command line options and Gtk::Plug properly

I'm trying to interface with the xfce4-settings-manager which I was successfully able to do in the standard c gtk+-3.0 libraries, but I've been struggling to replicate it in gtkmm3. xfce4-settings-manager passes a --socked-id option to the client, and the client is meant to use a GtkPlug to connect to the socket via the id. As I mentioned before I was successful in writing it in C, and I've put that code in a github gist here. I prefer to use C++ as a means to learn the language in a more applied way and also because of its higher functionality to C.
I've struggled with the proper way to handle arguments to the proper way to use Gtk::Plug with hours of research and little results. If anyone can provide some insight into the proper way/documentation to handle command line arguments and GtkPlugs in gtkmm3 that would be greatly appreciated, and if you could provide any examples that would also be greatly appreciated. Thank you in advance!
Here is an example similar to yours, in C++ with Gtkmm 3:
#include <string>
#include <gtkmm.h>
#include <gtkmm/plug.h>
// Simple command line argument parser.
//
// Documented here:
//
// https://gitlab.gnome.org/GNOME/glibmm/-/blob/master/examples/options/main.cc
//
class CmdArgParser : public Glib::OptionGroup
{
public:
CmdArgParser(const std::string& p_name, const std::string& p_description, const std::string& p_help)
: Glib::OptionGroup{p_name, p_description, p_help}
{
// Define the 'socket ID' argument options:
Glib::OptionEntry socketIDArg;
socketIDArg.set_long_name("socket-id");
socketIDArg.set_short_name('s');
socketIDArg.set_flags(Glib::OptionEntry::FLAG_IN_MAIN);
socketIDArg.set_description("Settings manager socket");
// Register it in the parser. It value will be recorded in m_socketID for later usage.
add_entry(socketIDArg, m_socketID);
}
// Override this to handle errors. I skipped it for simplicity.
// void on_error(Glib::OptionContext& context, const Glib::Error& error) override;
::Window GetSocketID() const
{
return m_socketID;
}
private:
int m_socketID = 0;
};
// This is what is going to be plugged into xfce4-settings-manager:
//
// Documented here:
//
// https://developer.gnome.org/gtkmm-tutorial/3.22/sec-plugs-sockets-example.html.en
//
class SettingsPlug : public Gtk::Plug
{
public:
SettingsPlug(::Window p_socketID)
: Gtk::Plug{p_socketID}
{
m_button.set_label("A plug with Gtkmm3!");
add(m_button);
show_all_children();
}
private:
Gtk::Button m_button;
};
int main(int argc, char** argv)
{
auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example.plug");
// Parse command line arguments and retreive socket ID:
Glib::init();
setlocale(LC_ALL, "");
Glib::OptionContext context;
CmdArgParser parser{
"Socket ID",
"Command line argument for socket ID communication.",
"No help available, sorry"
};
context.set_main_group(parser);
context.parse(argc, argv);
::Window socketID = parser.GetSocketID();
// Handle plug:
SettingsPlug plug{socketID};
plug.show();
app->run(plug);
return 0;
}
I have removed error handling and the usage of Glade files to simplify the code. You can build it with:
g++ main.cpp -o example.out `pkg-config --cflags --libs gtkmm-3.0`

How to use a global variable for "configurations" in multiple tests in Googletest framework

I am using Google test framework for C++. Each file includes a config.hpp which defined a global configuration variable. I would like to define my config in a variable, not a compile-time const or constexpr. How can I define the dependencies to have the same variable in different files that are linked together? Do I have to use a singleton? Can I avoid that? Is there a better recommended way to use multiple test files xUnit style?
My config file: config.hpp:
#pragma once
struct {
const float tolerance = 0.001;
// ...
} CONFIG_VAR;
Each test *.cpp source file is like:
#include "gtest/gtest.h"
#include "core/config.hpp"
TEST(a, b) { ... }
My main file:
#include "gtest/gtest.h"
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
I compile and link using:
em++ -I $GTEST_ROOT/googletest/include main_all_tests.cpp test_*.cpp
PS. My problem is multiple definition of the variable CONFIG_VAR.
My solution is based on a related question.
Everything you need is right here at the Google Test's official repository on GitHub.
Anyway, to sharing something in the same file test you do it like that:
class YourTestCase : public ::testing::Test
{
protected:
virtual void SetUp()
{
globalObject = new YourObject();
}
virtual void TearDown() {
delete globalObject;
globalObject = nullptr;
}
Object * globalObject = nullptr;
};
so, in your test cases:
TEST_F(YourTestCase, TestOne) {
ASSERT_EQ("your value here", globalObject->getValue());
}
TEST_F(YourTestCase, TestTwo) {
ASSERT_EQ("your value here", globalObject->getValue());
}
TEST_F(YourTestCase, TestThree) {
ASSERT_EQ("your value here", globalObject->getValue());
}
Note.: Pay attention to the function's name. It is TEST_F not TEST.
On the other hand, if what you want to do it is at the test program level ― sharing something among files, you will need to set up an environment object. Something like this:
Environment * AddGlobalTestEnvironment(Environment * env);
I have never worked with that before, so I can not tell you so much about it, but there is more information at that link I shared above. Usually, global variables make the code harder to read and may cause problems. You'd be better off avoiding them.

How to use header file in SystemC Hello World program?

I'm migrating from C++ to SystemC, met following basic questions. (I've searched in google, but only got examples in a single .cpp file). Thanks in advance.
I know following "hello.cpp" works:
//hello.cpp
#include "systemc.h"
SC_MODULE (hello_world) {
SC_CTOR (hello_world) {
}
void say_hello() {
cout << "Hello World.\n";
}
};
int sc_main(int argc, char* argv[]) {
hello_world hello("HELLO");
hello.say_hello();
return(0);
}
Question 1: How can I separate it into hello.h and hello.cpp? Following code is in C++, I don't know how to create the equivalent SystemC code.
//hello.h
class hello_world
{
public:
hello_world();
void say_hello();
};
//hello.cpp
hello_world::hello_world()
{
}
hello_world::say_hello()
{
cout << "Hello World.\n";
}
Question 2: How to create nested class in SystemC? E.g. what is the equivalent SystemC code according to following C++?
class foo
{
public:
int fooAttr1;
class bar
{
public:
int barAttr1;
};
};
Question 3: Where is the best place to specify an attribute/operation's scope? (public/protected/private).
When separating out the implementation from the declarations in SystemC, you can do it the normal way as it is done in C++.
But when you want a constructor with more than one argument(except the default one i.e. SC_CTOR accepts the module name) you will have to define your own constructor.
And if the module has SystemC processes(SC_THREAD, SC_METHOD, SC_CTHREAD) then you will have to use the SC_HAS_PROCESS macro to indicate that your module has process/es.
And regarding nested class it is the same thing as in C++.
I am not sure what you mean by the 3rd question.
regarding your 3rd question: you can do same as you usually do in a C++ program. The best place to specify an attribute/operation's scope is the declaration part of the SC_MODULE, whether you put it in cpp or header file.
In a SystemC design, normally only the ports and constructor/destructor should be defined as public to allow other modules to connect with it, unless you have a strong reason and want to break the modularity of a systemc design to access explicitly the member functions of a module.

How to implement a Singleton in an application with DLL

I have an application (in MS Visual Studio) that contains 3 projects:
main (the one that contains the main function)
device (models some hardware device)
config (contains some configuration for both other projects)
So the dependency graph is:
main depends on device, which depends on config
main depends on config
The config project contains a Singleton, which holds some configuration parameters.
I decided to turn the device project into a DLL. When i did this, it seems that i got two instances of the Singleton in the config project! I guess this is a classic problem, which might have a good solution. So how can i fix this?
I reproduced the problem with the following (relatively small) code. Of course, in my case there are some 30 projects, not just 3. And i would like to make just 1 DLL (if possible).
// config.h
#pragma once
#include <string>
#include <map>
class Config
{
public:
static void Initialize();
static int GetConfig(const std::string& name);
private:
std::map<std::string, int> data;
};
// config.cpp
#include "config.h"
static Config g_instance;
void Config::Initialize()
{
g_instance.data["one"] = 1;
g_instance.data["two"] = 2;
}
int Config::GetConfig(const std::string& name)
{
return g_instance.data[name];
}
// device.h
#pragma once
#ifdef _DLL
#define dll_cruft __declspec( dllexport )
#else
#define dll_cruft __declspec( dllimport )
#endif
class dll_cruft Device
{
public:
void Work();
};
// device.cpp
#include "device.h"
#include <iostream>
#include "config.h"
void Device::Work()
{
std::cout << "Device is working: two = " << Config::GetConfig("two") << '\n';
}
// main.cpp
#include <iostream>
#include "config.h"
#include "device.h"
int main()
{
std::cout << "Before initialization in application: one = " << Config::GetConfig("one") << '\n';
Config::Initialize();
std::cout << "After initialization in application: one = " << Config::GetConfig("one") << '\n';
Device().Work();
std::cout << "After working in application: two = " << Config::GetConfig("two") << '\n';
}
Output:
Before initialization in application: one = 0
After initialization in application: one = 1
Device is working: two = 0
After working in application: two = 2
Some explanations on what the code does and why:
Main application starts
The first print is just to show that the singleton is not initialized yet
Main application initializes the singleton
The first print shows that the initialization worked
Main application starts the "hardware device"
Inside the DLL, the singleton is not initialized! I expect it to output two = 2
The last print shows that the singleton is still initialized in main application
When I ran into this same problem I solved it by creating another DLL whose sole purpose is to manage the singleton instance. All attempts to get a pointer to the singleton call the function inside this new DLL.
You can decide where singleton should reside and then expose it to other consumers.
Edited by OP:
For example, i want that the config instance appear only in the EXE (not DLL).
Turn the instance into a pointer
static Config* g_instance;
Add a separate initializing function to device's exported functions:
void InitializeWithExisting(Config* instance) {g_instance=instance;}
After initializing the singleton normally, use the second initialization:
Config::Initialize();
Config::InitializeWithExisting();
I believe that defining and accessing singleton instance this way might solve your problem:
Config& getInstance()
{
static Config config;
return config;
}
This way you also don't need to have (and call) the Initialize method, you can use constructor for initializing, that will be called automatically when you call getInstance for the first time.