I would like to add a header to a log file which would describe the format of the data in the log file. The purpose of this is to perform post analysis in python pandas. I am looking to add a header something like this (the first line is the header, the rest is data).
The header needs to be added when the file is initialized and only be at the head of the file.
YYYYMMDDHHMMSS.MS,TYPE,SIMULATION_TIME,PLATFORM_ID,LATITUDE,LONGITUDE,ELEVATION
20231008091747.442690,[info],0,drone[0],21.281,-157.796,41.7117
20231008091747.448856,[info],0,drone[2],21.2576,-157.799,6.23664
20231008091747.448907,[info],0,drone[3],21.2576,-157.799,6.23664
20231008091747.453667,[info],0,server,21.3,-157.8,196.413
20231008091747.454533,[info],0.033,drone[0],21.281,-157.796,41.6859
20231008091747.454550,[info],0.033,drone[2],21.2576,-157.799,6.24225
Update to this post...
adding my source file.
I use the log elsewhere in my code using the following
LOG_POSITION << simTime() << "," << getFullName() << "," << latitude << "," << longitude << "," << test;
Here is my log header file. logger.h
#pragma once
#define BOOST_LOG_DYN_LINK 1
#include <boost/log/expressions.hpp>
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup.hpp>
// This header needs to be implemented and called only once
// during initialization
#define LOG_POSITION_HEADER BOOST_LOG_SEV(my_logger::get(), boost::log::trivial::info)
#define LOG_POSITION BOOST_LOG_SEV(my_logger::get(), boost::log::trivial::info)
#define WARN1 BOOST_LOG_SEV(my_logger::get(), boost::log::trivial::warning)
#define ERROR1 BOOST_LOG_SEV(my_logger::get(), boost::log::trivial::error)
#define SYS_LOGFILE "../resources/logs/droneMovements.log"
typedef boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> logger_t;
BOOST_LOG_GLOBAL_LOGGER(my_logger, logger_t)
The cc file logger.cc
#include "logger.h"
namespace attrs = boost::log::attributes;
namespace expr = boost::log::expressions;
namespace logging = boost::log;
BOOST_LOG_GLOBAL_LOGGER_INIT(my_logger, logger_t)
{
logger_t lg;
logging::add_common_attributes();
logging::add_file_log(
boost::log::keywords::file_name = SYS_LOGFILE,
boost::log::keywords::format = (expr::stream
<< expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y%m%d%H%M%S.%f,")
<< expr::smessage)
);
logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::info);
return lg;
}
You don't show any code, so you're having us guess/make assumptions.
Let me assume that you use any of the setup helpers to arrive at a
text_file_backend, e.g.:Live On Coliru
Creating a log file containing:
The Problem
The textfile backend likes to govern the actual file name (having capabilities of rotating log files and naming according to certain pattern and limits).
Also, the initialization is lazy, so even if it seemed you can get the current filename from the backend like:
It will not give a name until after the sink actually gets activated, which happens at the first log. By then it will be too late to insert a header.
A solution?
Depending on your actual context, you may not need all the features, and you could perhaps get away with opening your own stream and logging to that:
Which does give the expected outcome:
Elegance?
This is not very elegant in that it uses a static variable. This limitation is due to
add_console_logonly (which as the name implies, expects existing globals likestd::clog).So you can be more verbose in the initialization to avoid the static:
Whether or not this is actual elegant or worth it, is a decision I'll happily leave to your discretion.