GCC Code Coverage Report


Directory: ./
File: log.h
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 5 5 100.0%
Functions: 2 2 100.0%
Branches: 1 2 50.0%

Line Branch Exec Source
1 #pragma once
2 /*
3 * This file is part of the Falcon Player (FPP) and is Copyright (C)
4 * 2013-2022 by the Falcon Player Developers.
5 *
6 * The Falcon Player (FPP) is free software, and is covered under
7 * multiple Open Source licenses. Please see the included 'LICENSES'
8 * file for descriptions of what files are covered by each license.
9 *
10 * This source file is covered under the LGPL v2.1 as described in the
11 * included LICENSE.LGPL file.
12 */
13
14 #include <string>
15 #include <vector>
16
17 /*
18 * Define the allowed levels of Logging
19 */
20 typedef enum {
21 LOG_ERR = 1,
22 LOG_WARN,
23 LOG_INFO,
24 LOG_DEBUG,
25 LOG_EXCESSIVE
26 } LogLevel;
27
28 /*
29 * A Logger Instance.
30 * In the future, this could be adjusted to allow different Instances
31 * to go to different files
32 */
33
34 // LAYOUT RULE: this class is plugin ABI, even though no plugin ever names it.
35 // The VB_* macros below expand to a member of the single FPPLogger::INSTANCE, so
36 // a plugin bakes in "INSTANCE + N * sizeof(FPPLoggerInstance)" at compile time
37 // and passes that address to libfpp's _LogWrite() as an FPPLoggerInstance&.
38 // Change sizeof(FPPLoggerInstance) -- or insert/remove a facility in FPPLogger --
39 // and every already-built plugin points at the middle of some other facility.
40 // What comes back is not a std::string, so facility.name.c_str() hands strlen() a
41 // pointer made of raw character bytes and fppd dies on the plugin's first log
42 // line. Adding the crashRingCapture bool below did exactly that: it grew this
43 // class from 28 to 32 bytes on 32-bit ARM, and plugins built against the older
44 // header resolved VB_PLUGIN 52 bytes short, landing inside the SSO buffer of
45 // Control's name. Plugin.h publishes fingerprints for this layout (they live
46 // there, not here, because that is the header every plugin includes textually
47 // rather than through the PCH) and the loader compares them, so a slip is
48 // refused at dlopen -- but only for plugins built since those fingerprints
49 // existed. If a member is genuinely needed here, treat it as an ABI change and
50 // weigh a FPP_PLUGIN_API_VERSION bump, which is the only thing that reaches
51 // binaries already in the field.
52 class FPPLoggerInstance {
53 public:
54 39296 FPPLoggerInstance(std::string name, bool crashRingCapture = true) {
55
1/2
✓ Branch 0 taken 39296 times.
✗ Branch 1 not taken.
39296 this->name = name;
56 39296 this->crashRingCapture = crashRingCapture;
57 39296 }
58 LogLevel level = LOG_INFO;
59 std::string name;
60
61 // Whether this facility's lines are kept in the crash-time ring (see
62 // CrashLogRingDump). Off for the per-frame data facilities: HexDump()
63 // emits at LogInfo, and DebugOutput::SendData calls it ungated on every
64 // frame, so a single such output would both burn CPU formatting into the
65 // ring and evict the entire history within a frame or two. The ring is
66 // for reconstructing state changes, and channel data is not one.
67 bool crashRingCapture = true;
68 };
69
70 /*
71 * Class to hold all the Instances
72 */
73 class FPPLogger {
74 public:
75 static FPPLogger INSTANCE;
76 35 const std::vector<FPPLoggerInstance*>& allInstances() { return all; }
77 void Init();
78 bool SetLevel(std::string name, LogLevel level);
79 bool SetLevel(const char* name, const char* level);
80 void SetAllLevel(LogLevel level);
81 int MinimumLogLevel();
82 std::string GetLogLevelString();
83 FPPLoggerInstance General = FPPLoggerInstance("General");
84 FPPLoggerInstance ChannelOut = FPPLoggerInstance("ChannelOut", false);
85 FPPLoggerInstance ChannelData = FPPLoggerInstance("ChannelData", false);
86 FPPLoggerInstance Command = FPPLoggerInstance("Command");
87 FPPLoggerInstance E131Bridge = FPPLoggerInstance("E131Bridge");
88 FPPLoggerInstance Effect = FPPLoggerInstance("Effect");
89 FPPLoggerInstance MediaOut = FPPLoggerInstance("MediaOut");
90 FPPLoggerInstance Playlist = FPPLoggerInstance("Playlist");
91 FPPLoggerInstance Schedule = FPPLoggerInstance("Schedule");
92 FPPLoggerInstance Sequence = FPPLoggerInstance("Sequence");
93 FPPLoggerInstance Settings = FPPLoggerInstance("Settings");
94 FPPLoggerInstance Control = FPPLoggerInstance("Control");
95 FPPLoggerInstance Sync = FPPLoggerInstance("Sync");
96 ;
97 FPPLoggerInstance Plugin = FPPLoggerInstance("Plugin");
98 FPPLoggerInstance GPIO = FPPLoggerInstance("GPIO");
99 FPPLoggerInstance HTTP = FPPLoggerInstance("HTTP");
100
101 private:
102 std::vector<FPPLoggerInstance*> all;
103 };
104
105 #define VB_GENERAL FPPLogger::INSTANCE.General
106 #define VB_ALL FPPLogger::INSTANCE.General /* Over Load */
107 #define VB_CHANNELOUT FPPLogger::INSTANCE.ChannelOut
108 #define VB_CHANNELDATA FPPLogger::INSTANCE.ChannelData
109 #define VB_COMMAND FPPLogger::INSTANCE.Command
110 #define VB_E131BRIDGE FPPLogger::INSTANCE.E131Bridge
111 #define VB_EFFECT FPPLogger::INSTANCE.Effect
112 #define VB_MEDIAOUT FPPLogger::INSTANCE.MediaOut
113 #define VB_PLAYLIST FPPLogger::INSTANCE.Playlist
114 #define VB_SCHEDULE FPPLogger::INSTANCE.Schedule
115 #define VB_SEQUENCE FPPLogger::INSTANCE.Sequence
116 #define VB_SETTING FPPLogger::INSTANCE.Settings
117 #define VB_CONTROL FPPLogger::INSTANCE.Control
118 #define VB_SYNC FPPLogger::INSTANCE.Sync
119 #define VB_PLUGIN FPPLogger::INSTANCE.Plugin
120 #define VB_GPIO FPPLogger::INSTANCE.GPIO
121 #define VB_HTTP FPPLogger::INSTANCE.HTTP
122
123 #define EXCESSIVE_LOG_LEVEL_WARNING "A Log Level is set to Excessive"
124 #define DEBUG_LOG_LEVEL_WARNING "A Log Level is set to Debug"
125
126 //extern int logLevel;
127 //extern char logLevelStr[16];
128 //extern int logMask;
129 //extern char logMaskStr[1024];
130
131 #define LogErr(facility, format, args...) _LogWrite(__FILE__, __LINE__, LOG_ERR, facility, format, ##args)
132 #define LogInfo(facility, format, args...) _LogWrite(__FILE__, __LINE__, LOG_INFO, facility, format, ##args)
133 #define LogWarn(facility, format, args...) _LogWrite(__FILE__, __LINE__, LOG_WARN, facility, format, ##args)
134 #define LogDebug(facility, format, args...) _LogWrite(__FILE__, __LINE__, LOG_DEBUG, facility, format, ##args)
135 #define LogExcess(facility, format, args...) _LogWrite(__FILE__, __LINE__, LOG_EXCESSIVE, facility, format, ##args)
136
137 void _LogWrite(const char* file, int line, int level, FPPLoggerInstance& facility, const char* format, ...);
138 void _LogWrite(const char* file, int line, int level, FPPLoggerInstance& facility, const std::string &str, ...);
139 bool WillLog(int level, FPPLoggerInstance& facility);
140
141 // Every log call reads a facility's level, on whatever thread it runs, while
142 // the API and settings change it on others: read and write it through these.
143 LogLevel FacilityLevel(FPPLoggerInstance& facility);
144 void SetFacilityLevel(FPPLoggerInstance& facility, LogLevel level);
145
146 // True when a line at this level/facility is retained in the crash-time ring
147 // even though the configured log level would otherwise discard it.
148 bool CrashLogRingWillCapture(int level, FPPLoggerInstance& facility);
149
150 // Stop accepting new lines. Called at the top of the crash handler so its own
151 // logging does not evict the pre-crash history.
152 void CrashLogRingFreeze();
153
154 // Write the retained lines to fd, oldest first. Async-signal-safe: no locks,
155 // no allocation, write() only -- so it is usable from a crash handler that may
156 // hold the very locks the normal log path needs.
157 //
158 // PRIVACY: these are log lines, and FPP's logs carry host names, LAN addresses
159 // and discovered-device identifiers. Treat the output as log content -- it
160 // belongs in a crash report only at the share level that already ships
161 // logs/fppd.log, never at "stack traces only".
162 void CrashLogRingDump(int fd);
163
164 // Truncates a value before it goes into a log line - use for anything whose
165 // length isn't bounded by code (a Variable's value, a condition/command-list
166 // JSON blob, raw command output), as opposed to things like names/paths that
167 // are inherently short. Without this, e.g. an If condition checking a
168 // Variable that happens to hold a fetched web page can turn a single log
169 // line into hundreds of KB (found in practice: a 450KB Variable value logged
170 // in full from Condition.cpp's per-leaf trace). Appends a size marker when
171 // truncated so it's obvious data was cut, not silently dropped.
172 std::string TruncateForLog(const std::string& s, size_t maxLen = 200);
173
174 void SetLogFile(const char* filename, bool toStdOut = true);
175
176 // Drop the stdout copy of any line that made it into the log file. Only fppd
177 // wants this: it runs as `fppd -f` under systemd, so every line it logs would
178 // otherwise also be captured by journald, doubling the volume for a copy that
179 // dies with the boot. Leave it off (the default) in the small services -- their
180 // output is what `journalctl -u <service>` is expected to show. An interactive
181 // run (stdout is a TTY) echoes to the console regardless.
182 void SetSuppressDuplicateStdOut(bool suppress);
183 int loggingToFile(void);
184 void logVersionInfo(void);
185
186 bool SetLogLevel(const char* newLevel);
187 bool SetLogLevelComplex(std::string& input); /*parse debug:schedule,player;excess:mqtt*/
188 bool SetLogLevelComplex(const char* input); /*parse debug:schedule,player;excess:mqtt*/
189 std::string LogLevelToString(LogLevel level); /* Convert Level to String Equivilanent */
190