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.