Index: cpp/common/loggers/loggers.cpp
===================================================================
--- cpp/common/loggers/loggers.cpp	(revision 390)
+++ cpp/common/loggers/loggers.cpp	(revision 390)
@@ -0,0 +1,124 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#include "loggers.h"
+#include <common/stl-util.h>
+
+void _logMessageSingleLine(const char *obj, const char *method, int level, const char *msg)
+{
+	tlsGetRef(message_handler_manager_instance).send(obj, method, level, msg);
+}
+
+THREAD_LOCAL_DEF(LoggerManager, message_handler_manager_instance);
+
+void LoggerManager::send(int position, const char *obj, const char *method, int level, const char *msg)
+{
+	if (position >= (int)loggers.size()) position = loggers.size() - 1;
+	bool blocked = false;
+	for (int i = position; i >= 0; i--)
+	{
+		LoggerBase *logger = loggers[i];
+		if ((!(logger->options & LoggerBase::Paused)) &&
+			((!blocked) || (logger->options & LoggerBase::CannotBeBlocked)))
+		{
+			logger->handle(obj, method, level, msg);
+			if (!(logger->options & LoggerBase::DontBlock)) blocked = true;
+		}
+	}
+}
+
+int LoggerManager::add(LoggerBase *logger)
+{
+	logger->manager = this;
+	loggers.push_back(logger);
+	return loggers.size() - 1;
+}
+
+void LoggerManager::remove(int i)
+{
+	LoggerBase *h = loggers[i];
+	h->manager = NULL;
+	loggers.erase(loggers.begin() + i);
+}
+
+void LoggerManager::remove(LoggerBase *logger)
+{
+	int index = find(logger);
+	if (index >= 0)
+		remove(index);
+}
+
+void LoggerManager::removeAll()
+{
+	while (loggers.size() > 0)
+		remove(loggers.size() - 1);
+}
+
+//////////////////////////////////
+
+void LoggerBase::send(const char *obj, const char *method, int level, const char *msg)
+{
+	if (!isEnabled()) return;
+	int position = manager->find(this);
+	if (position >= 0) manager->send(position - 1, obj, method, level, msg);
+}
+
+void LoggerBase::logPrintf(const char *obj, const char *method, int level, const char *msg, ...)
+{
+	if (!isEnabled()) return;
+	string buf;
+	va_list argptr;
+	va_start(argptr, msg);
+	buf = ssprintf_va(msg, argptr);
+	va_end(argptr);
+	send(obj, method, level, buf.c_str());
+}
+
+
+void LoggerBase::enable()
+{
+	if (isEnabled()) return;
+	tlsGetRef(message_handler_manager_instance).add(this);
+}
+
+void LoggerBase::disable()
+{
+	if (!isEnabled()) return;
+	tlsGetRef(message_handler_manager_instance).remove(this);
+}
+
+void LoggerBase::pause()
+{
+	if (isPaused()) return;
+	options |= Paused;
+}
+
+void LoggerBase::resume()
+{
+	if (!isPaused()) return;
+	options &= ~Paused;
+}
+
+/////////////////////////////////
+
+void LoggerToMemory::handle(const char *obj, const char *method, int level, const char *msg)
+{
+	if (level > maxlevel) maxlevel = level;
+	if (level >= LOG_INFO) infocount++;
+	if (level >= LOG_WARN) warncount++;
+	if (level >= LOG_ERROR) errcount++;
+
+	if (level >= minleveltostore)
+	{
+		storedcount++;
+		if (options & (StoreFirstMessage | StoreAllMessages))
+		{
+			if (!((options&StoreFirstMessage) && (msgs.length() > 0)))
+			{
+				if (msgs.length() > 0) msgs += '\n';
+				msgs += ssprintf(LOG_FORMAT, LOG_LEVEL[level + 1], obj, method, msg);
+			}
+		}
+	}
+}
Index: cpp/common/loggers/loggers.h
===================================================================
--- cpp/common/loggers/loggers.h	(revision 390)
+++ cpp/common/loggers/loggers.h	(revision 390)
@@ -0,0 +1,121 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef _COMMON_LOGGERS_H_
+#define _COMMON_LOGGERS_H_
+
+#include <common/log.h>
+#include <common/threads.h>
+#include <common/nonstd_stl.h>
+
+class LoggerBase;
+
+class LoggerManager
+{
+	friend class LoggerBase;
+	vector<LoggerBase*> loggers;
+	void send(int position, const char *obj, const char *method, int level, const char *msg);
+public:
+	int find(LoggerBase *logger)
+	{
+		vector<LoggerBase*>::iterator it = std::find(loggers.begin(), loggers.end(), logger);
+		return it == loggers.end() ? -1 : std::distance(loggers.begin(), it);
+	}
+	int add(LoggerBase *logger);
+	void remove(int i);
+	void remove(LoggerBase *logger);
+	void removeAll();
+	void send(const char *obj, const char *method, int level, const char *msg)
+	{
+		send(loggers.size() - 1, obj, method, level, msg);
+	}
+	~LoggerManager() { removeAll(); }
+};
+
+extern THREAD_LOCAL_DECL(LoggerManager, message_handler_manager_instance);
+
+////////////////////////////////////////
+
+class LoggerBase
+{
+	friend class LoggerManager;
+protected:
+	LoggerManager* manager;
+	int options;
+
+public:
+
+	enum LoggerOptions
+	{
+		DontBlock = 1, CannotBeBlocked = 2, Enable = 4, Paused = 8
+	};
+
+	void logPrintf(const char *o, const char *m, int w, const char *bl, ...);
+	void send(const char *obj, const char *method, int level, const char *msg);
+
+	bool isEnabled() { return manager ? true : false; }
+	void enable();
+	void disable();
+	bool isPaused() { return (options & Paused) != 0; }
+	void pause();
+	void resume();
+
+	LoggerBase(int opts = 0) :manager(NULL), options(opts)
+	{
+		if (options&Enable) enable();
+	}
+	virtual ~LoggerBase()
+	{
+		disable();
+	}
+
+	virtual void handle(const char *obj, const char *method, int level, const char *msg) {}
+};
+
+///////////////////////////////////////////
+
+class LoggerToMemory : public LoggerBase
+{
+protected:
+	int maxlevel, minleveltostore, errcount, warncount, infocount, storedcount;
+	string msgs;
+
+public:
+
+	void reset() { maxlevel = LOG_INFO - 1; errcount = warncount = infocount = storedcount = 0; msgs = ""; }
+
+	enum Options2
+	{
+		StoreFirstMessage = 16, StoreAllMessages = 32
+	};
+
+	int getErrorCount()       { return errcount; }
+	int getWarningCount()     { return warncount; }
+	int getInfoCount()        { return infocount; }
+	int getStoredCount()      { return storedcount; }
+	int getErrorLevel()       { return maxlevel; }
+	const string getMessages() { return msgs; }
+
+	LoggerToMemory(int opts = 0, int minimal_level_to_store = LOG_ERROR) :LoggerBase(opts), minleveltostore(minimal_level_to_store)
+	{
+		reset();
+	}
+
+	void handle(const char *obj, const char *method, int level, const char *msg);
+};
+
+class RedirectingLogger : public LoggerBase
+{
+	LoggerManager *other_manager;
+public:
+	RedirectingLogger(LoggerManager *other_mgr, int opts = 0)
+		:LoggerBase(opts), other_manager(other_mgr) {}
+
+	void handle(const char *obj, const char *method, int level, const char *msg)
+	{
+		other_manager->send(obj, method, level, msg);
+	}
+};
+
+#endif
Index: cpp/common/loggers/loggertostdout.cpp
===================================================================
--- cpp/common/loggers/loggertostdout.cpp	(revision 390)
+++ cpp/common/loggers/loggertostdout.cpp	(revision 390)
@@ -0,0 +1,23 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#include "loggertostdout.h"
+#ifdef SHP
+#include <FBaseSys.h> //AppLog
+#else
+#include <stdio.h>
+#endif
+
+void LoggerToStdout::handle(const char *obj, const char *method, int level, const char *msg)
+{
+	if (level < -1) level = -1; else if (level>3) level = 3;
+#ifdef SHP
+	AppLog(LOG_FORMAT "\n",LOG_LEVEL[level+1],obj,method,msg);
+#else
+	if (file)
+		file->printf(LOG_FORMAT "\n", LOG_LEVEL[level + 1], obj, method, msg);
+	else
+		printf(LOG_FORMAT "\n", LOG_LEVEL[level + 1], obj, method, msg);
+#endif
+}
Index: cpp/common/loggers/loggertostdout.h
===================================================================
--- cpp/common/loggers/loggertostdout.h	(revision 390)
+++ cpp/common/loggers/loggertostdout.h	(revision 390)
@@ -0,0 +1,19 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef _STDOUT_LOGGER_H_
+#define _STDOUT_LOGGER_H_
+
+#include "loggers.h"
+#include <common/virtfile/virtfile.h>
+
+class LoggerToStdout : public LoggerBase
+{
+	VirtFILE *file;
+public:
+	LoggerToStdout(int opts = 0, VirtFILE *_file = NULL) :LoggerBase(opts), file(_file) {}
+	void handle(const char *obj, const char *method, int level, const char *msg);
+};
+
+#endif
