1 /*
2 * SRT - Secure, Reliable, Transport
3 * Copyright (c) 2018 Haivision Systems Inc.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 */
10
11 #include <map>
12 #include <vector>
13 #include <string>
14 #include <iterator>
15 #include <algorithm>
16 #include <cctype>
17 #include "logsupport.hpp"
18 #include "../srtcore/srt.h"
19 #include "../srtcore/utilities.h"
20
21 using namespace std;
22
23 // This is based on codes taken from <sys/syslog.h>
24 // This is POSIX standard, so it's not going to change.
25 // Haivision standard only adds one more severity below
26 // DEBUG named DEBUG_TRACE to satisfy all possible needs.
27
28 map<string, int> srt_level_names
29 {
30 { "alert", LOG_ALERT },
31 { "crit", LOG_CRIT },
32 { "debug", LOG_DEBUG },
33 { "emerg", LOG_EMERG },
34 { "err", LOG_ERR },
35 { "error", LOG_ERR }, /* DEPRECATED */
36 { "fatal", LOG_CRIT }, // XXX Added for SRT
37 { "info", LOG_INFO },
38 // WTF? Undefined symbol? { "none", INTERNAL_NOPRI }, /* INTERNAL */
39 { "notice", LOG_NOTICE },
40 { "note", LOG_NOTICE }, // XXX Added for SRT
41 { "panic", LOG_EMERG }, /* DEPRECATED */
42 { "warn", LOG_WARNING }, /* DEPRECATED */
43 { "warning", LOG_WARNING },
44 //{ "", -1 }
45 };
46
47
48
SrtParseLogLevel(string level)49 srt_logging::LogLevel::type SrtParseLogLevel(string level)
50 {
51 using namespace srt_logging;
52
53 if ( level.empty() )
54 return LogLevel::fatal;
55
56 if ( isdigit(level[0]) )
57 {
58 long lev = strtol(level.c_str(), 0, 10);
59 if ( lev >= SRT_LOG_LEVEL_MIN && lev <= SRT_LOG_LEVEL_MAX )
60 return LogLevel::type(lev);
61
62 cerr << "ERROR: Invalid loglevel number: " << level << " - fallback to FATAL\n";
63 return LogLevel::fatal;
64 }
65
66 int (*ToLower)(int) = &std::tolower; // manual overload resolution
67 transform(level.begin(), level.end(), level.begin(), ToLower);
68
69 auto i = srt_level_names.find(level);
70 if ( i == srt_level_names.end() )
71 {
72 cerr << "ERROR: Invalid loglevel spec: " << level << " - fallback to FATAL\n";
73 return LogLevel::fatal;
74 }
75
76 return LogLevel::type(i->second);
77 }
78
79 struct ToLowerFormat
80 {
operator ()ToLowerFormat81 char operator()(char in)
82 {
83 if (islower(in))
84 return in;
85 if (isupper(in))
86 return tolower(in);
87 if (in == '_')
88 return '-';
89
90 throw std::invalid_argument("Wrong FA name - please check the definition in scripts/generate-logging-defs.tcl file");
91 }
92 };
93
Install(string upname,int value)94 void LogFANames::Install(string upname, int value)
95 {
96 string id;
97 transform(upname.begin(), upname.end(), back_inserter(id), ToLowerFormat());
98 namemap[id] = value;
99 }
100
101 // See logsupport_appdefs.cpp for log FA definitions
102 LogFANames srt_transmit_logfa_names;
103
SrtLogFAList()104 const map<string, int> SrtLogFAList()
105 {
106 return srt_transmit_logfa_names.namemap;
107 }
108
SrtParseLogFA(string fa,set<string> * punknown)109 set<srt_logging::LogFA> SrtParseLogFA(string fa, set<string>* punknown)
110 {
111 using namespace srt_logging;
112
113 set<LogFA> fas;
114
115 // The split algo won't work on empty string.
116 if ( fa == "" )
117 return fas;
118
119 auto& names = srt_transmit_logfa_names.namemap;
120
121 if ( fa == "all" )
122 {
123 for (auto entry: names)
124 {
125 // Skip "general", it's always on
126 if (entry.first == "general")
127 continue;
128 fas.insert(entry.second);
129 }
130 return fas;
131 }
132
133 int (*ToLower)(int) = &std::tolower;
134 transform(fa.begin(), fa.end(), fa.begin(), ToLower);
135
136 vector<string> xfas;
137 size_t pos = 0, ppos = 0;
138 for (;;)
139 {
140 if ( fa[pos] != ',' )
141 {
142 ++pos;
143 if ( pos < fa.size() )
144 continue;
145 }
146 size_t n = pos - ppos;
147 if ( n != 0 )
148 xfas.push_back(fa.substr(ppos, n));
149 ++pos;
150 if ( pos >= fa.size() )
151 break;
152 ppos = pos;
153 }
154
155 for (size_t i = 0; i < xfas.size(); ++i)
156 {
157 fa = xfas[i];
158 int* pfa = map_getp(names, fa);
159 if (!pfa)
160 {
161 if (punknown)
162 punknown->insert(fa); // If requested, add it back silently
163 else
164 cerr << "ERROR: Invalid log functional area spec: '" << fa << "' - skipping\n";
165 continue;
166 }
167
168 fas.insert(*pfa);
169 }
170
171 return fas;
172 }
173
ParseLogFASpec(const vector<string> & speclist,string & w_on,string & w_off)174 void ParseLogFASpec(const vector<string>& speclist, string& w_on, string& w_off)
175 {
176 std::ostringstream son, soff;
177
178 for (auto& s: speclist)
179 {
180 string name;
181 bool on = true;
182 if (s[0] == '+')
183 name = s.substr(1);
184 else if (s[0] == '~')
185 {
186 name = s.substr(1);
187 on = false;
188 }
189 else
190 name = s;
191
192 if (on)
193 son << "," << name;
194 else
195 soff << "," << name;
196 }
197
198 const string& sons = son.str();
199 const string& soffs = soff.str();
200
201 w_on = sons.empty() ? string() : sons.substr(1);
202 w_off = soffs.empty() ? string() : soffs.substr(1);
203 }
204
205
206