Skip to content

Commit

Permalink
Merge pull request #447 from NikitaZotov/feat/improve_logger
Browse files Browse the repository at this point in the history
[memory][utils][logger] Allow to create multiple loggers
  • Loading branch information
NikitaZotov authored Dec 26, 2024
2 parents 6829983 + f2a79d3 commit ecf499a
Show file tree
Hide file tree
Showing 23 changed files with 901 additions and 322 deletions.
2 changes: 2 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ See documentation, to learn more about using new API.

### Changed

- Allow multiple instances of `ScLogger` class
- Rename `ScLog` to `ScLogger`
- Description of project in Readme
- Working directory for each test has been changed to the test's source dir
- `gtest` and `benchmark` are installed via Conan or OS package managers instead of using them as git submodules
Expand Down
99 changes: 85 additions & 14 deletions docs/sc-memory/api/cpp/core/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,8 @@ To declare your own exceptions inherit from class `ScException`.
class MyException final : public ScException
{
public:
explicit MyException(std::string const & description, std::string const & message)
explicit MyException(
std::string const & description, std::string const & message)
: ScException("MyException: " + description, message)
{}
};
Expand All @@ -443,22 +444,92 @@ SC_NOT_IMPLEMENTED("This code is not implemented.");

### **ScLogger**

There are some standard macros which you can use for logging your code. They are encapsulate the class `ScLogger` to
prevent unappropriated access to it and provide metaprogramming during message logging.
The `ScLogger` class provides a robust logging mechanism for your code.

| Macro | Message prefix | Message color | Log levels |
|------------------------|----------------|-------------------------------|-----------------------------|
| `SC_LOG_DEBUG(msg);` | `[Debug]` | `ScConsole::Color::Grey` | Debug |
| `SC_LOG_INFO(msg);` | `[Info]` | `ScConsole::Color::LightBlue` | Debug, Info |
| `SC_LOG_WARNING(msg);` | `[Warning]` | `ScConsole::Color::Yellow` | Debug, Info, Warning |
| `SC_LOG_ERROR(msg);` | `[Error]` | `ScConsole::Color::Red` | Debug, Info, Warning, Error |
To create an instance of ScLogger, you can use the constructor that specifies the logging type (console or file), the log file name (if applicable), and the initial log level. Here’s how to do it:

Now you can not add log levels. But if you want to use another prefixes or colors in logging you can use
`SC_LOG_INFO_COLOR(msg, color);`. It prints colored info message. Look color constants in `ScConsole::Color`.
```cpp
// Create a logger that logs to the console with Info level
utils::ScLogger logger(
utils::ScLogger::ScLogType::Console, "", utils::ScLogLevel::Info);

// Create a logger that logs to a file with Debug level
utils::ScLogger fileLogger(
utils::ScLogger::ScLogType::File, "log_file.txt", utils::ScLogLevel::Debug);
```
Once you have created an instance of ScLogger, you can call its various methods to manage logging.
#### **Message** (**Error**, **Warning**, **Info**, **Debug**)
Use the `Message` method to log messages at different severity levels:
```cpp
logger.Info("This is an informational message.");
// or
// logger.Message(
// utils::ScLogLevel::Info,
// "This is an informational message.",
// ScConsole::Color::Grey);
fileLogger.Error("An error occurred while processing.");
// or
// fileLogger.Message(
// utils::ScLogLevel::Error,
// "An error occurred while processing.",
// ScConsole::Color::Red);
```

It prints colored info message. Look color constants in `ScConsole::Color`.

#### **SetLogLevel**

You can change the log level dynamically:

```cpp
logger.SetLogLevel(utils::ScLogLevel::Warning);
```

#### **Mute** and **Unmute**

Control whether logs are outputted:

```cpp
logger.Mute(); // Mute logging
logger.Unmute(); // Unmute logging
```

#### **SetPrefix**

Customize prefix for logs:

```cpp
logger.SetPrefix("MyAgent: ");

logger.Info("It is info message");
// Output: MyAgent: Is info message
```

#### **Clear**

Clear any open file streams or flush logs if necessary:

```cpp
logger.Clear();
```

#### **Log levels**

The following macros are available for logging messages at different severity levels:

| Method | Message prefix | Message color | Log levels |
|-----------|----------------|-------------------------------|-----------------------------|
| `Debug` | `[Debug]` | `ScConsole::Color::Grey` | Debug |
| `Info` | `[Info]` | `ScConsole::Color::LightBlue` | Debug, Info |
| `Warning` | `[Warning]` | `ScConsole::Color::Yellow` | Debug, Info, Warning |
| `Error` | `[Error]` | `ScConsole::Color::Red` | Debug, Info, Warning, Error |

Log level can be configured in config file `sc-machine.ini`. Change parameter `log_level` in group `[sc-memory]` by one
from the list `[Debug, Info, Warning, Error]`. See [Config file example](../../../../build/config.md) to
learn more about groups and their parameters.
These macros simplify the process of logging messages by automatically formatting them with appropriate prefixes and colors based on their severity levels.

## **Extended API**

Expand Down
2 changes: 2 additions & 0 deletions docs/sc-memory/api/cpp/extended/agents/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ ScResult MyAgent::DoProgram(
`ScAgent` class has field `m_context`. It is an object of `ScAgentContext` class. You can use to complete operations in sc-memory. See [**C++ Agent context API**](agent_context.md) to learn more about accessible methods.
`ScAgent` class has field `m_logger`. It is an object of `ScLogger` class. Use it to logging your code. See [**C++ Core API**](../../core/api.md) to learn how to use it.
!!! warning
If you don't catch sc-exceptions in `DoProgram` then sc-machine will catch them and will finish action with error and will warn you about it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ ScResult ScAgentCalculateSetPower::DoProgram(ScAction & action)
// argument for the action. So we need to check that the action has argument.
if (!m_context.IsElement(setAddr))
{
SC_AGENT_LOG_ERROR("Action does not have argument.");
m_logger.Error("Action does not have argument.");
// output: "ScAgentCalculateSetPower: Action does not have argument."
return action.FinishWithError();
}
Expand Down Expand Up @@ -203,7 +203,7 @@ ScResult ScAgentCalculateSetPower::DoProgram(ScAction & action)

action.FormResult(
setAddr, arcCommonAddr, setPowerAddr, arcAccessAddr, nrelSetPowerAddr);
SC_AGENT_LOG_DEBUG("Set power was counted: " << setPower << ".");
m_logger.Debug("Set power was counted: " << setPower << ".");

// At the end of the agent's program, you must call one of three methods
// (`FinishSuccessfully`, `FinishUnsuccessfully`, `FinishWithError`)
Expand Down
1 change: 1 addition & 0 deletions sc-memory/sc-memory/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ file(GLOB SOURCES CONFIGURE_DEPENDS
"include/sc-memory/*.hpp"
"include/sc-memory/*/*.hpp"
"include/sc-memory/*/*.tpp"
"include/sc-memory/*/*/*.tpp"
)

find_glib()
Expand Down
53 changes: 27 additions & 26 deletions sc-memory/sc-memory/include/sc-memory/_template/sc_agent.tpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ bool ScAgent<TScEvent, TScContext>::ValidateInitiationCondition(TScEvent const &
}
catch (utils::ScException const & exception)
{
SC_LOG_ERROR("Initiation condition template is not valid. " << exception.Message());
m_logger.Error("Initiation condition template is not valid. ", exception.Message());
}
return isFound;
}
Expand Down Expand Up @@ -299,7 +299,7 @@ bool ScAgent<TScEvent, TScContext>::ValidateResultCondition(TScEvent const & eve
}
catch (utils::ScException const & exception)
{
SC_LOG_ERROR("Result condition template is not valid. " << exception.Message());
m_logger.Error("Result condition template is not valid. ", exception.Message());
}
return isFound;
}
Expand Down Expand Up @@ -353,9 +353,10 @@ ScTemplate ScAgent<TScEvent, TScContext>::BuildInitiationConditionTemplate(
auto const & iteratorIt = eventToEventTripleIterators.find(eventClassAddr);
if (iteratorIt == eventToEventTripleIterators.cend())
{
SC_LOG_WARNING(
"Event class for agent class `" << this->GetName()
<< "` is unknown. It is impossible to check initiation condition template.");
m_logger.Warning(
"Event class for agent class `",
this->GetName(),
"` is unknown. It is impossible to check initiation condition template.");
return ScTemplate();
}

Expand Down Expand Up @@ -443,44 +444,44 @@ bool ScAgent<TScEvent, TScContext>::GenerateCheckTemplateParams(
checkTemplateParams.Add(connectorVarAddr, connectorAddr);
else
{
SC_LOG_WARNING(
"Initiation condition template of agent class `"
<< this->GetName()
<< "` checks initiated sc-event incorrectly. Maybe initiation condition template has triple with incorrect "
"sc-element types to "
"substitute sc-elements involved in initiated sc-event.");
m_logger.Warning(
"Initiation condition template of agent class `",
this->GetName(),
"` checks initiated sc-event incorrectly. Maybe initiation condition template has triple with incorrect "
"sc-element types to "
"substitute sc-elements involved in initiated sc-event.");
checkTemplateParams = ScTemplateParams();
return false;
}
}
else
{
SC_LOG_WARNING(
"Initiation condition template of agent class `"
<< this->GetName()
<< "` checks initiated sc-event incorrectly. Maybe initiation condition template does not have triple to "
"substitute sc-elements involved in initiated sc-event.");
m_logger.Warning(
"Initiation condition template of agent class `",
this->GetName(),
"` checks initiated sc-event incorrectly. Maybe initiation condition template does not have triple to "
"substitute sc-elements involved in initiated sc-event.");
return false;
}

if (eventTripleIterator->Next())
{
SC_LOG_WARNING(
"Initiation condition template of agent class `"
<< this->GetName()
<< "` checks initiated sc-event incorrectly. Maybe initiation condition template has triple to "
"substitute sc-elements involved in initiated sc-event twice.");
m_logger.Warning(
"Initiation condition template of agent class `",
this->GetName(),
"` checks initiated sc-event incorrectly. Maybe initiation condition template has triple to "
"substitute sc-elements involved in initiated sc-event twice.");
checkTemplateParams = ScTemplateParams();
return false;
}
}
else
{
SC_LOG_WARNING(
"Initiation condition template of agent class `"
<< this->GetName()
<< "` doesn't check initiated sc-event. Maybe agent initiation condition template does not have sc-event "
"subscription sc-element.");
m_logger.Warning(
"Initiation condition template of agent class `",
this->GetName(),
"` doesn't check initiated sc-event. Maybe agent initiation condition template does not have sc-event "
"subscription sc-element.");
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,21 +435,25 @@ std::function<void(typename TScAgent::TEventType const &)> ScAgentManager<TScAge
};

TScAgent agent;
agent.m_logger.SetPrefix(agent.GetName() + ": ");
agent.SetInitiator(event.GetUser());
agent.SetImplementation(agentImplementationAddr);

std::string const & agentName = GetAgentClassName(&agent.m_context, agent);
// SC_LOG_INFO("Agent `" << agentName << "` reacted to primary initiation condition.");
agent.m_logger.Info("Agent `", agentName, "` reacted to primary initiation condition.");

if (agent.IsActionClassDeactivated())
{
SC_LOG_WARNING(
"Agent `" << agentName << "` was finished because actions with class `" << agent.GetActionClass().Hash()
<< "` are deactivated.");
agent.m_logger.Warning(
"Agent `",
agentName,
"` was finished because actions with class `",
agent.GetActionClass().Hash(),
"` are deactivated.");
return PostCallback();
}

// SC_LOG_INFO("Agent `" << agentName << "` started checking initiation condition.");
agent.m_logger.Info("Agent `", agentName, "` started checking initiation condition.");
bool isInitiationConditionCheckedSuccessfully = false;
try
{
Expand All @@ -458,24 +462,24 @@ std::function<void(typename TScAgent::TEventType const &)> ScAgentManager<TScAge
}
catch (utils::ScException const & exception)
{
SC_LOG_ERROR(
"Not able to check initiation condition template, because error was occurred. " << exception.Message());
agent.m_logger.Error(
"Not able to check initiation condition template, because error was occurred. ", exception.Message());
}

if (!isInitiationConditionCheckedSuccessfully)
{
SC_LOG_WARNING(
"Agent `" << agentName << "` was finished because its initiation condition was checked unsuccessfully.");
agent.m_logger.Warning(
"Agent `", agentName, "` was finished because its initiation condition was checked unsuccessfully.");
return PostCallback();
}
// SC_LOG_INFO("Agent `" << agentName << "` finished checking initiation condition.");
agent.m_logger.Info("Agent `", agentName, "` finished checking initiation condition.");

ScAction action = ResolveAction(event, agent);
ScResult result;

try
{
SC_LOG_INFO("Agent `" << agentName << "` started performing action.");
agent.m_logger.Info("Agent `", agentName, "` started performing action.");
if constexpr (HasOverride<TScAgent>::DoProgramWithEventArgument::value)
result = agent.DoProgram(event, action);
else
Expand Down Expand Up @@ -503,13 +507,13 @@ std::function<void(typename TScAgent::TEventType const &)> ScAgentManager<TScAge
}

if (result == SC_RESULT_OK)
SC_LOG_INFO("Agent `" << agentName << "` finished performing action successfully.");
agent.m_logger.Info("Agent `", agentName, "` finished performing action successfully.");
else if (result == SC_RESULT_NO)
SC_LOG_INFO("Agent `" << agentName << "` finished performing action unsuccessfully.");
agent.m_logger.Info("Agent `", agentName, "` finished performing action unsuccessfully.");
else
SC_LOG_INFO("Agent `" << agentName << "` finished performing action with error.");
agent.m_logger.Info("Agent `", agentName, "` finished performing action with error.");

// SC_LOG_INFO("Agent `" << agentName << "` started checking result condition.");
agent.m_logger.Info("Agent `", agentName, "` started checking result condition.");
bool isResultConditionCheckedSuccessfully = false;
try
{
Expand All @@ -518,15 +522,16 @@ std::function<void(typename TScAgent::TEventType const &)> ScAgentManager<TScAge
}
catch (utils::ScException const & exception)
{
SC_LOG_ERROR("Not able to check result condition template, because error was occurred. " << exception.Message());
agent.m_logger.Error(
"Not able to check result condition template, because error was occurred. ", exception.Message());
}

if (!isResultConditionCheckedSuccessfully)
{
SC_LOG_WARNING("Result condition of agent `" << agentName << "` checked unsuccessfully.");
agent.m_logger.Warning("Result condition of agent `", agentName, "` checked unsuccessfully.");
return PostCallback();
}
// SC_LOG_INFO("Agent `" << agentName << "` finished checking result condition.");
agent.m_logger.Info("Agent `", agentName, "` finished checking result condition.");

return PostCallback();
};
Expand Down
38 changes: 38 additions & 0 deletions sc-memory/sc-memory/include/sc-memory/_template/utils/sc_log.tpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* This source file is part of an OSTIS project. For the latest info, see http://ostis.net
* Distributed under the MIT License
* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
*/

#include "sc-memory/utils/sc_logger.hpp"

#include "sc-memory/utils/sc_message.hpp"

namespace utils
{

template <typename T, typename... ARGS>
void ScLogger::Error(T const & t, ARGS const &... others)
{
Message(ScLogLevel::Level::Error, utils::impl::Message(t, others...), ScConsole::Color::Red);
}

template <typename T, typename... ARGS>
void ScLogger::Warning(T const & t, ARGS const &... others)
{
Message(ScLogLevel::Level::Warning, utils::impl::Message(t, others...), ScConsole::Color::Yellow);
}

template <typename T, typename... ARGS>
void ScLogger::Info(T const & t, ARGS const &... others)
{
Message(ScLogLevel::Level::Info, utils::impl::Message(t, others...), ScConsole::Color::Grey);
}

template <typename T, typename... ARGS>
void ScLogger::Debug(T const & t, ARGS const &... others)
{
Message(ScLogLevel::Level::Debug, utils::impl::Message(t, others...), ScConsole::Color::LightBlue);
}

} // namespace utils
Loading

0 comments on commit ecf499a

Please sign in to comment.