FCF 2.0 development in progress...
> > > > > >
[News] [C++ Libraries API] [C++ Downloads] [Donate to the project] [Contacts]

typedef DataFactory from class fcf::NTest::Logger

Type: fcf::NTest::Logger::DataFactory

Definition: typedef std::function<fcf::NTest::SharedPtrAny(fcf::NTest::Logger&, fcf::NTest::Logger::OutputTarget&)> DataFactory;

Package: fcfTest

File: test.hpp

Available from version: 1.2.1

A factory function for creating type-erased user data for loggers.

The fcf::NTest::Logger::DataFactory is a functional type used to lazily initialize and provide metadata for loggers. It is primarily utilized within fcf::NTest::Logger::Format and fcf::NTest::Logger::Prefix via the dataFactory property.

When a logger processes a message for a specific fcf::NTest::Logger::OutputTarget and a specific format/prefix, it checks if the associated data has already been created. If not, it invokes the DataFactory to generate a new fcf::NTest::SharedPtrAny object. This mechanism ensures that expensive-to-construct metadata is only created when actually needed and is reused for subsequent log entries directed to the same target.

The factory function receives two arguments:

  • The instance of the fcf::NTest::Logger currently performing the operation.
  • The specific fcf::NTest::Logger::OutputTarget for which the data is being created.

Example: Lazy Metadata Initialization

Demonstrating how to use fcf::NTest::Logger::DataFactory to attach a custom context object to a logger format, ensuring it is created only once per output target.

#define FCF_TEST_IMPLEMENTATION #include <fcfTest/test.hpp> #include <iostream> #include <string> // 1. Define a custom structure that will be stored in the logger's metadata struct SessionContext { std::string sessionId; int userId; }; FCF_TEST_DECLARE("DataFactoryDemo", "Logger", "LazyInit") { // Trigger logging // The factory will be called here because it's the first time this format is used fcf::NTest::log() << "First log entry" << std::endl; fcf::NTest::log() << "Second log entry" << std::endl; } int main(int a_argc, char* a_argv[]) { // Create a DataFactory that produces our SessionContext // This lambda will be called only when the logger needs to initialize data for a target fcf::NTest::Logger::DataFactory factory = [](fcf::NTest::Logger& logger, fcf::NTest::Logger::OutputTarget& target) { // We return a SharedPtrAny containing our custom object return fcf::NTest::SharedPtrAny::make<SessionContext>(SessionContext{"SESSION-99", 42}); }; // Configure a custom format that uses this factory fcf::NTest::Logger& logger = fcf::NTest::logger(); fcf::NTest::Logger::Format format; format.name = "session-format"; format.dataFactory = factory; format.handler = []( fcf::NTest::Logger&, fcf::NTest::Logger::MessageContext& context) { // Try to retrieve the data from the context SessionContext* ctx = context.data->cast<SessionContext>(); if (ctx) { context.message = "[ID: " + ctx->sessionId + "] " + context.message; } }; // Register the format logger.appendFormat(format); bool error = false; fcf::NTest::cmdRun(a_argc, a_argv, fcf::NTest::CRM_RUN, &error); return error ? 1 : 0; }

Output:

[ID: SESSION-99] Performing the test: "DataFactoryDemo" -> "Logger" -> "LazyInit" ... [ID: SESSION-99] > First log entry [ID: SESSION-99] > Second log entry [ID: SESSION-99] [SUCCESS] Test completed successfully (0.000`008`413 sec) [ID: SESSION-99] [ID: SESSION-99] [SUCCESS] All tests were completed. [ID: SESSION-99] Tests: 1 passed, 0 failed, 0 skipped, 1 total [ID: SESSION-99] Duration: 0.000`008`413 sec

The application must be run by specifying the format via a command-line parameter:

app --test-format "session-format"

Notice that the SessionContext was created only once, even though we logged two messages. The DataFactory was invoked only for the first message to initialize the metadata for the current output target.