FBB::Log(3bobcat)

✨ NAME ✨

FBB::Log β€” an std::ostream that handles log messages, and honestly it's serving πŸ’…

This is FBB::Log(3bobcat), bestie, and we're about to make log messages make sense.


🌸 SYNOPSIS 🌸

#include <bobcat/log>
Linking option: -lbobcat

πŸ’– DESCRIPTION πŸ’–

Okay so, the class FBB::Log defines an std::ostream using an FBB::LogBuf std::streambuf. It's the whole point of it: you send log-messages to the (r)syslog stream, or to a file (and that file is configurable, periodt). If you want the deets about LogBuf itself, go read the logbuf(3bobcat) man-page. πŸ‘‘

Which (parts of) messages actually get logged is something you configure β€” either with FBB::level combined with the Log member setLevel, or with the function operator combined with the str member (peep the members operator() and str). And by default? Every single thing you insert into a Log object gets logged. No filter, no cap. 🫢

Objects of the level class (cf. level(3bobcat)) can be inserted to specify insertion 'forces' for whatever info gets inserted into Log objects after that. And here's the vibe check: only if those 'forces' exceed the Log object's insertion 'resistances' (see the member setLevel) does the info actually get logged. It's giving push and pull, lowkey.

A single log-insertion statement can contain multiple level calls. If it does, then each level call updates the 'force' of the insertions that follow that level call. Chain them, bestie. ✨

Info inserted into Log objects without inserting level objects (or before the first level object) is always logged (see also the Examples section).

Alternatively you can log info using category-selector characters. The member str(std::string const &active) defines the characters that can be used to define a non-hierarchical logging process. E.g., str("abc") defines the log-identifying characters 'a', 'b', and 'c', which you can then use to define log-statements for each of those categories. These log-identifying characters may be redefined, and doing that activates only those log-statements whose identifying characters were specified in the last call of the str member. Last call wins, no takebacks. πŸ’€

So even though hierarchical and non-hierarchical logging can both be used in a single program, they operate in a mutually exclusive way β€” like, they do not share the aux cord. Once hierarchical logging is defined, the non-hierarchical categories get erased. And once non-hierarchical categories are defined, the hierarchical resistance level gets set to its maximum value, which effectively suppresses hierarchical logging. It's one or the other, iykyk.

By default, logged messages get prepended by time stamps. Following the time stamps, a delimiter gets inserted β€” by default that's a single space character. Delimiters are immediately appended to time stamps, and inserted messages are immediately appended to delimiters. So it's all just glued together in a row. When you're specifying text as delimiters, consider starting and ending the delimiter's text with space characters, so the delimiter is visually separated from the time stamp and from the info that gets inserted after it. Trust me, your eyes will thank you. 🌈


πŸŽ€ NAMESPACE πŸŽ€

FBB

All constructors, members, operators and manipulators mentioned in this man-page are defined in the namespace FBB.


πŸ¦‹ INHERITS FROM πŸ¦‹

std::ostream


⭐ ENUMERATIONS ⭐

The enumeration TimeStamps is defined in the namespace FBB, primarily for initializing FBB::LogBuf objects. It's used with Log members as well. It has the following values:

  • NOTIMESTAMPS β€” log-messages will not have timestamps prepended to them. Fresh, clean, undated. πŸ“
  • TIMESTAMPS β€” log-messages will have timestamps prepended to them. Classic.
  • UTCTIMESTAMPS β€” log-messages will have timestamps showing the UTC time prepended to them. Worldwide vibe. 🌍

The enumeration LogManipulator is used to handle special or exceptional situations through manipulators. It is defined in the namespace FBB and has the following two values:

  • FATAL β€” when inserting FATAL into a Log object, an FBB::Exception exception is thrown (see operator<< below). 🚨 Dramatic and deserved.
  • nl β€” when inserting nl into a Log object, a \n character is inserted into the current line. If time stamps are requested, the next line will not begin with a time stamp. It's used to allow a single log message to occupy multiple textual lines. The next logged line is not indented over the width of the omitted time stamp. If that's what you'd prefer: the time stamp occupies 15 character positions (not counting the width of the delimiter, see the CONSTRUCTORS section below). If a level specification is active, it remains active at insertions following nl. πŸ’…
  • fnl β€” when inserting fnl (forced new line) into a Log object, the current line ends even if the currently active insertion 'force' (set by level) is lower than the Log object's 'resistance' level. If a level specification is active, it remains active at insertions following fnl. Forced means forced, bestie. πŸ”₯
  • endl or \n β€” when inserting endl or \n, the current line is ended and the next logged line starts with a timestamp (unless timestamps are suppressed). The endl manipulator is the standard ostream manipulator: when inserted into a Log object its buffer is flushed. The scope of a level specification ends at \n or endl. E.g.,
log.setLevel(2);
log << level(1) << "first line\n"
       "second line\n";

results in second line (preceded by a timestamp) being logged.

Also, quick aside: the manpage says LogManipulator has "two values" and then hits you with four bullets. Not me noticing, but okay, we move. πŸ™ˆ

πŸ‘‘ CONSTRUCTORS πŸ‘‘

  • Log() β€” the default constructor creates a Log object which isn't yet associated with a stream to log messages on. The member open (see below) may be used to define such a stream. By default, all messages are preceded by a time stamp (see the description of the member setTimestamp below), and a single space character is inserted as delimiter immediately beyond the time stamp. The member open can be used to modify the default delimiter.
  • Log(std::ostream &out, char const *delim = " ") β€” this constructor creates a Log object logging its messages to the provided std::ostream object. By default, all messages are preceded by a time stamp (see the description of the member setTimestamp below). The parameter delim is inserted immediately beyond the time stamp. If a delimiter should not be used, an empty string or a 0-pointer may be specified. πŸ™…
  • FBB::Log(std::string const &filename, std::ios::openmode mode = std::ios::out | std::ios::app, char const *delim = " ") β€” this constructor creates a Log object logging its messages to the named file. If filename == "&1" logmessages are written to the standard output stream. If filename == "&2" logmessages are written to the standard error stream. By default the file is created if not existing, and all messages are appended to the stream. Also by default all messages are preceded by time stamps (see the description of the member setTimestamp below). The parameter delim is inserted immediately beyond the time stamp. If a delimiter should not be used, an empty string or a 0-pointer may be specified. ✨

Copy and move constructors (and assignment operators) are not available. Don't try it, she said no. πŸ’…

πŸ’… MEMBER FUNCTIONS πŸ’…

okay bestie, housekeeping first: every single member of std::ostream is yours to play with, because Log inherits from that class. no gatekeeping.

  • size_t level() const β€” hands you back the log level that's currently set, like, the value from the latest setLevel() call. by default it's zero, which means everything gets inserted into the log stream. no filter, no crumbs left behind πŸ’–
  • std::ostream &level(size_t useLevel) β€” this one sets the log-level of the messages that are gonna get inserted. a message shows up when useLevel is at least equal to the level specified by setLevel. the max level? that's std::numeric_limits<size_t>::max(). and if you don't want even those messages in your ostream, deactivate the stream with off() (details below, bestie πŸ‘‡). the level you set here stays active until another level call changes it. alternatively you can set the level of inserted messages by dropping an FBB::level manipulator into a Log object β€” see level(3bobcat).
  • void off() β€” stops log messages from being generated. periodt. it gets cancelled by calling on (next bullet, iykyk).
  • void on(size_t logLevel = 0) β€” reactivates logging (like, after off was called earlier) and sets the level that inserted info must at least have, to logLevel. after on, and unless you say otherwise (with level, for instance), all inserted information is accepted by the Log object ✨
  • void open(std::string const &filename, std::ios::openmode mode = std::ios::out | std::ios::app, char const *delim = " ") β€” this member (re)associates a Log object with the named file. if filename == "&1" the logmessages go to the standard output stream. if filename == "&2" the logmessages go to the standard error stream. by default the file gets created if it doesn't exist, and all messages get appended to the stream. also by default, every message is preceded by time stamps (peep the setTimestamp member below for the tea). the delim parameter is inserted immediately beyond the time stamp. if you don't want a delimiter, pass an empty string or a 0-pointer 🌸
  • void setLevel(size_t resistance) β€” defines the resistance’ when inserting information into a Logobject. information is inserted if the level set by thelevelmember is at least equal to *resistance*. aftersetLevel, and unless you say otherwise (by using level, for example), all inserted information is accepted by the Logobject. <red>heads up tho:</red>setLeveldoes **not** reactivate logging after you calledoff. to bring logging back after off, you gotta call on`. no shortcuts πŸ’€
  • void setTimestamp(FBB::TimeStamps stamp, char const *delim = " ") β€” (de)activates time stamp prepending. use the value FBB::TIMESTAMPS to prepend time stamps, FBB::NOTIMESTAMPS to suppress them. a timestamp is 15 characters long and shows the abbreviated month's name, two digits for the day number of the month, and the (local or UTC) time of the current message β€” exactly the way it usually shows up in messages in /var/log files. example: Aug 05 13:52:23. the delim parameter goes immediately beyond the time stamp. if a delimiter is inappropriate, an empty string or a 0-pointer works. and when you specify stamps as FBB::NOTIMESTAMPS, delim also gets ignored πŸŽ€
  • std::string const &str() const β€” returns the currently set bunch of characters that can be specified by Log's function call operator to insert a log-entry. by default, no characters are specified.
  • void str(std::string const &chars) β€” the argument here is a std::string defining the characters that can be specified by Log's function call operator to insert a log-entry. if the function call operator specifies a character that isn't in chars, that log message gets ignored. by default, no characters are specified πŸ™ˆ

<div align="center">---</div>

🌟 STATIC MEMBERS 🌟

  • FBB::Log &initialize(std::string const &filename, std::ios::openmode mode = std::ios::out | std::ios::app, char const *delim = " ") β€” returns a reference to a static Log object. it may only be called once, or an FBB::Exception exception gets thrown. it associates a static Log object with the named file.

if filename == "&1" logmessages are written to the standard output stream. if filename == "&2" logmessages are written to the standard error stream. by default the file is created if it doesn't exist, and all messages are appended to the stream. also by default all messages are preceded by time stamps (go read the setTimestamp member description above for that one). the delim parameter is inserted immediately beyond the time stamp. if a delimiter should not be used, an empty string or a 0-pointer may be specified πŸ’œ

  • FBB::Log &instance() β€” returns a reference to a static Log object, available after calling Log::initialize. if you call it before Log::initialize() an FBB::Exception exception is thrown. so like, read the room and call them in order, bestie 😭

<div align="center">---</div>

✨ OVERLOADED OPERATORS ✨

  • Log &operator()(char ch) β€” if the function's argument is found in the characters specified at the str member, then subsequent insertions β€” up to and including inserting std::endl, or the fnl or FATAL LogManipulator β€” are logged. if the function's argument is not found in the characters specified at the str member, then subsequent insertions are ignored. calling this member suppresses hierarchical insertions until the setLevel member gets called πŸ¦‹
  • Log &operator<<(Log &, LogManipulator) β€” this operator inserts a LogManipulator into a Log object. when inserting FBB::FATAL, an FBB::Exception is thrown. when inserting FBB::nl, the line is terminated and the next insertion won't start with a time stamp. when inserting FBB::fnl, the line is terminated and the next insertion will start with a time stamp (if applicable). after calling this insertion operator with the FATAL or fnl LogManipulator, value category-based insertions are suppressed until the function-call operator is called 🌈
  • Log &operator<<(Log &log, Type const &type) β€” this operator is defined as a template, where Type represents any type that can be inserted into a std::ostream. the value type is inserted into the Log object. slay, generic πŸ’…
  • Log &operator<<(Log &log, Type &(*fun)(Type &type)) β€” here fun represents the standard ostream and ios_base manipulators, which lets you insert manipulators like std::endl and std::setw into Log objects. iconic behaviour, honestly.
  • std::ostream &::operator<<(std::ostream &str, FBB::LogManipulator) β€” this operator is defined outside of the FBB namespace. it's kept around for backward compatibility with previous bobcat versions, and it calls operator<<(Log, LogManipulatr) when &str can dynamically be casted to a Log *. if not, then the operator performs no actions. it's giving legacy but make it cute πŸŽ€

<div align="center">---</div>

🧚 EXAMPLE 🧚

okay so here's the whole vibe in code. observe, learn, absorb 🫢

#include <iostream>
#include <iomanip>

#include <bobcat/log>
#include <bobcat/level>

using namespace std;
using namespace FBB;

int main()
{
//    Log &log = Log::initialize("&1"); // uses the static Log object
    Log log;                        // explicitly defining a Log object
//    log.open("/tmp/out");           // or at once: Log log{ "/tmp/out" }

    log << "This message is written to cout" << nl <<
           setw(16) << ’ ’ << "occupying multiple lines\n";

    log.off();
    log << "This message is not shown\n";
    log << "This message is not shown\n";
    log << fnl;
    log << "This message is not shown\n";

    log.on(2);
    log << "This message is shown\n";

    log << level(0) << "not shown" << level(2) << "shown at level 2\n";
    log << level(3) << "at level(3)" << level(1) << "not shown" << fnl;

    log << "separate new line\n";

    log << level(2) << "in business again\n";
    log << "final line\n";

    log.str("ab");

    log(’a’) << "hello a!" << endl;
    log(’b’) << "hello b!" << nl <<
                setw(16) << ’ ’ << "so far, so good" << endl;

    log << "not shown" << endl;

    log(’c’) << "not shown\n";
    log << "not shown\n";

    log.setLevel(2);
    log << level(2) << "in business again\n";
}

<div align="center">---</div>

πŸ“ FILES πŸ“

  • bobcat/log β€” defines the class interface πŸ’–

<div align="center">---</div>

πŸ‘€ SEE ALSO πŸ‘€

bobcat(7), exception(3bobcat), level(3bobcat), logbuf(3bobcat), syslogstream(3bobcat)

(down the rabbit hole we go, bestie πŸ‡)

<div align="center">---</div>

πŸ’€ BUGS πŸ’€

the nl and fnl manipulators are received by the Log objects' LogBufs as, respectively, characters 0 and 1. since log files in practice only received printable characters, this shouldn't cause any problems. ngl, it's fine 🫢

<div align="center">---</div>

🌸 BOBCAT PROJECT FILES 🌸

Debian Bobcat project files:

  • libbobcat6: debian package containing the shared library, changelog and copyright note πŸŽ€
  • libbobcat-dev: debian package containing the static library, headers, manual pages, and developer info πŸŽ€

<div align="center">---</div>

πŸ‘‘ BOBCAT πŸ‘‘

Bobcat is an acronym of `Brokken’s Own Base Classes And Templates’. like, the name itself is a flex, no cap.

<div align="center">---</div>

this is free software, distributed under the terms of the GNU General Public License (GPL). free as in freedom, bestie πŸ’œ

<div align="center">---</div>

πŸ’– AUTHOR πŸ’–

Frank B. Brokken (f.b.brokken@rug.nl). absolute icon, main character energy, we stan 🌟


and that's a wrap on FBB::Log(3bobcat), part 2 of 2!! this whole masterpiece shipped as libbobcat-dev_6.15.01, dated 2005-2026, and if you need to find it again in the wild it answers to FBB::Log(3bobcat). go forth and log responsibly, bestie, mwah πŸ’‹βœ¨

πŸ“¦ where this page comes from