1 //
2 // Copyright © 2019,2022 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #pragma once
7
8 #include <armnn/Utils.hpp>
9 #include <ctype.h>
10 #include <iostream>
11 #include <algorithm>
12 #include <memory>
13 #include <string>
14 #include <utility>
15 #include <vector>
16
17 #include <armnn/Exceptions.hpp>
18
19 namespace armnn
20 {
21
LevelToString(LogSeverity level)22 inline std::string LevelToString(LogSeverity level)
23 {
24 switch(level)
25 {
26 case LogSeverity::Trace:
27 return "Trace";
28 case LogSeverity::Debug:
29 return "Debug";
30 case LogSeverity::Info:
31 return "Info";
32 case LogSeverity::Warning:
33 return "Warning";
34 case LogSeverity::Error:
35 return "Error";
36 case LogSeverity::Fatal:
37 return "Fatal";
38 default:
39 return "Log";
40 }
41 }
42
StringToLogLevel(std::string level)43 inline LogSeverity StringToLogLevel(std::string level)
44 {
45 // Transfer to lower case
46 std::transform(level.begin(), level.end(), level.begin(),
47 [](unsigned char c){ return std::tolower(c); }
48 );
49
50 if (level == "trace")
51 {
52 return LogSeverity::Trace;
53 }
54 else if (level == "debug")
55 {
56 return LogSeverity::Debug;
57 }
58 else if (level == "info")
59 {
60 return LogSeverity::Info;
61 }
62 else if (level == "warning")
63 {
64 return LogSeverity::Warning;
65 }
66 else if (level == "error")
67 {
68 return LogSeverity::Error;
69 }
70 else if (level == "fatal")
71 {
72 return LogSeverity::Fatal;
73 }
74 else
75 {
76 throw armnn::Exception("Unknown severity level for logging: '" + level +
77 "'. Valid options: trace, debug, info, warning, error, fatal");
78 }
79 }
80
81 class LogSink
82 {
83 public:
~LogSink()84 virtual ~LogSink(){};
85
86 virtual void Consume(const std::string&) = 0;
87 private:
88
89 };
90
91 class StandardOutputSink : public LogSink
92 {
93 public:
Consume(const std::string & s)94 void Consume(const std::string& s) override
95 {
96 std::cout << s << std::endl;
97 }
98 };
99
100 struct ScopedRecord
101 {
ScopedRecordarmnn::ScopedRecord102 ScopedRecord(const std::vector<std::shared_ptr<LogSink>>& sinks, LogSeverity level, bool enabled)
103 : m_LogSinks(sinks)
104 , m_Enabled(enabled)
105 {
106 if (enabled)
107 {
108 m_Os << LevelToString(level) << ": ";
109 }
110 }
111
~ScopedRecordarmnn::ScopedRecord112 ~ScopedRecord()
113 {
114 if (m_Enabled)
115 {
116 for (auto sink : m_LogSinks)
117 {
118 if (sink)
119 {
120 sink->Consume(m_Os.str());
121 }
122 }
123 }
124 }
125
126 ScopedRecord(const ScopedRecord&) = delete;
127 ScopedRecord& operator=(const ScopedRecord&) = delete;
128 ScopedRecord& operator=(ScopedRecord&&) = delete;
129
ScopedRecordarmnn::ScopedRecord130 ScopedRecord(ScopedRecord&& other)
131 : m_LogSinks(other.m_LogSinks)
132 , m_Os(std::move(other.m_Os))
133 , m_Enabled(other.m_Enabled)
134 {
135 // Disable the moved-from ScopedRecord, to prevent it from sending its (now empty) message to
136 // its sinks.
137 other.m_Enabled = false;
138 }
139
140 template<typename Streamable>
operator <<armnn::ScopedRecord141 ScopedRecord& operator<<(const Streamable& s)
142 {
143 if (m_Enabled)
144 {
145 m_Os << s;
146 }
147 return (*this);
148 }
149
150 private:
151 const std::vector<std::shared_ptr<LogSink>>& m_LogSinks;
152 std::ostringstream m_Os;
153 bool m_Enabled;
154 };
155
156 template<LogSeverity Level>
157 class SimpleLogger
158 {
159 public:
SimpleLogger()160 SimpleLogger()
161 : m_Sinks{std::make_shared<StandardOutputSink>()}
162 , m_Enable(true)
163 {
164 }
165
166 static SimpleLogger& Get();
167
Enable(bool enable=true)168 void Enable(bool enable = true)
169 {
170 m_Enable = enable;
171 }
172
StartNewRecord()173 ScopedRecord StartNewRecord()
174 {
175 return ScopedRecord(m_Sinks, Level, m_Enable);
176 }
177
RemoveAllSinks()178 void RemoveAllSinks()
179 {
180 m_Sinks.clear();
181 }
182
AddSink(std::shared_ptr<LogSink> sink)183 void AddSink(std::shared_ptr<LogSink> sink)
184 {
185 m_Sinks.push_back(sink);
186 }
187 private:
188 std::vector<std::shared_ptr<LogSink>> m_Sinks;
189 bool m_Enable;
190 };
191
192 void SetLogFilter(LogSeverity level);
193
194 void SetAllLoggingSinks(bool standardOut, bool debugOut, bool coloured);
195
196 enum class BoostLogSeverityMapping
197 {
198 trace,
199 debug,
200 info,
201 warning,
202 error,
203 fatal
204 };
205
ConvertLogSeverity(BoostLogSeverityMapping severity)206 constexpr LogSeverity ConvertLogSeverity(BoostLogSeverityMapping severity)
207 {
208 return static_cast<LogSeverity>(severity);
209 }
210
211
212 #define ARMNN_LOG(severity) \
213 armnn::SimpleLogger<ConvertLogSeverity(armnn::BoostLogSeverityMapping::severity)>::Get().StartNewRecord()
214
215 } //namespace armnn
216