1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chromeos/network/network_event_log.h"
9 #include "base/files/file_path.h"
10 #include "base/i18n/time_formatting.h"
11 #include "base/json/json_string_value_serializer.h"
12 #include "base/json/json_writer.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/strings/string_tokenizer.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/values.h"
19 #include "net/base/escape.h"
22 namespace network_event_log
{
26 class NetworkEventLog
;
27 NetworkEventLog
* g_network_event_log
= NULL
;
28 size_t g_max_network_event_log_entries
= 4000;
29 const char* kLogLevelName
[] = {"Error", "User", "Event", "Debug"};
32 LogEntry(const std::string
& file
,
35 const std::string
& event
,
36 const std::string
& description
);
38 std::string
ToString(bool show_time
,
41 bool format_html
) const;
42 void ToDictionary(base::DictionaryValue
*) const;
44 std::string
GetNormalText(bool show_desc
) const;
45 std::string
GetHtmlText(bool show_desc
) const;
46 std::string
GetAsJSON() const;
48 void SendToVLogOrErrorLog() const;
50 bool ContentEquals(const LogEntry
& other
) const;
56 std::string description
;
61 LogEntry::LogEntry(const std::string
& file
,
64 const std::string
& event
,
65 const std::string
& description
)
70 description(description
),
71 time(base::Time::Now()),
74 std::string
LogEntry::ToString(bool show_time
,
77 bool format_html
) const {
80 line
+= "[" + base::UTF16ToUTF8(base::TimeFormatTimeOfDay(time
)) + "] ";
82 std::string filestr
= format_html
? net::EscapeForHTML(file
) : file
;
83 line
+= base::StringPrintf("%s:%d ", file
.c_str(), file_line
);
85 line
+= format_html
? GetHtmlText(show_desc
) : GetNormalText(show_desc
);
87 line
+= base::StringPrintf(" (%d)", count
);
91 void LogEntry::ToDictionary(base::DictionaryValue
* output
) const {
92 output
->SetString("timestamp", base::TimeFormatShortDateAndTime(time
));
93 output
->SetString("level", kLogLevelName
[log_level
]);
94 output
->SetString("file",
95 base::StringPrintf("%s:%d ", file
.c_str(), file_line
));
96 output
->SetString("event", event
);
97 output
->SetString("description", description
);
100 std::string
LogEntry::GetAsJSON() const {
101 base::DictionaryValue entry
;
102 ToDictionary(&entry
);
104 JSONStringValueSerializer
serializer(&json
);
105 if (!serializer
.Serialize(entry
)) {
106 LOG(ERROR
) << "Failed to serialize to JSON";
111 std::string
LogEntry::GetNormalText(bool show_desc
) const {
112 std::string text
= event
;
113 if (show_desc
&& !description
.empty())
114 text
+= ": " + description
;
118 std::string
LogEntry::GetHtmlText(bool show_desc
) const {
120 if (log_level
== LOG_LEVEL_DEBUG
)
122 else if (log_level
== LOG_LEVEL_USER
)
124 else if (log_level
== LOG_LEVEL_ERROR
)
128 if (show_desc
&& !description
.empty())
129 text
+= ": " + net::EscapeForHTML(description
);
131 if (log_level
== LOG_LEVEL_DEBUG
)
133 else if (log_level
== LOG_LEVEL_USER
)
135 else if (log_level
== LOG_LEVEL_ERROR
)
140 void LogEntry::SendToVLogOrErrorLog() const {
141 const bool show_time
= true;
142 const bool show_file
= true;
143 const bool show_desc
= true;
144 const bool format_html
= false;
145 std::string output
= ToString(show_time
, show_file
, show_desc
, format_html
);
146 if (log_level
== LOG_LEVEL_ERROR
)
147 LOG(ERROR
) << output
;
152 bool LogEntry::ContentEquals(const LogEntry
& other
) const {
153 return file
== other
.file
&&
154 file_line
== other
.file_line
&&
155 event
== other
.event
&&
156 description
== other
.description
;
159 void GetFormat(const std::string
& format_string
,
165 base::StringTokenizer
tokens(format_string
, ",");
169 *format_html
= false;
170 *format_json
= false;
171 while (tokens
.GetNext()) {
172 std::string
tok(tokens
.token());
186 typedef std::list
<LogEntry
> LogEntryList
;
188 class NetworkEventLog
{
191 ~NetworkEventLog() {}
193 void AddLogEntry(const LogEntry
& entry
);
195 std::string
GetAsString(StringOrder order
,
196 const std::string
& format
,
200 LogEntryList
& entries() { return entries_
; }
203 LogEntryList entries_
;
205 DISALLOW_COPY_AND_ASSIGN(NetworkEventLog
);
208 void NetworkEventLog::AddLogEntry(const LogEntry
& entry
) {
209 if (!entries_
.empty()) {
210 LogEntry
& last
= entries_
.back();
211 if (last
.ContentEquals(entry
)) {
212 // Update count and time for identical events to avoid log spam.
214 last
.log_level
= std::min(last
.log_level
, entry
.log_level
);
215 last
.time
= base::Time::Now();
219 if (entries_
.size() >= g_max_network_event_log_entries
) {
220 const size_t max_error_entries
= g_max_network_event_log_entries
/ 2;
221 // Remove the first (oldest) non-error entry, or the oldest entry if more
222 // than half the entries are errors.
223 size_t error_count
= 0;
224 for (LogEntryList::iterator iter
= entries_
.begin(); iter
!= entries_
.end();
226 if (iter
->log_level
!= LOG_LEVEL_ERROR
) {
227 entries_
.erase(iter
);
230 if (++error_count
> max_error_entries
) {
231 // Too many error entries, remove the oldest entry.
232 entries_
.pop_front();
237 entries_
.push_back(entry
);
238 entry
.SendToVLogOrErrorLog();
241 std::string
NetworkEventLog::GetAsString(StringOrder order
,
242 const std::string
& format
,
245 if (entries_
.empty())
246 return "No Log Entries.";
248 bool show_time
, show_file
, show_desc
, format_html
, format_json
;
250 format
, &show_time
, &show_file
, &show_desc
, &format_html
, &format_json
);
253 base::ListValue log_entries
;
254 if (order
== OLDEST_FIRST
) {
256 if (max_events
> 0 && max_events
< entries_
.size()) {
257 // Iterate backwards through the list skipping uninteresting entries to
258 // determine the first entry to include.
259 size_t shown_events
= 0;
260 size_t num_entries
= 0;
261 for (LogEntryList::const_reverse_iterator riter
= entries_
.rbegin();
262 riter
!= entries_
.rend();
265 if (riter
->log_level
> max_level
)
267 if (++shown_events
>= max_events
)
270 offset
= entries_
.size() - num_entries
;
272 for (LogEntryList::const_iterator iter
= entries_
.begin();
273 iter
!= entries_
.end();
279 if (iter
->log_level
> max_level
)
282 log_entries
.AppendString((*iter
).GetAsJSON());
285 (*iter
).ToString(show_time
, show_file
, show_desc
, format_html
);
291 // Iterate backwards through the list to show the most recent entries first.
292 for (LogEntryList::const_reverse_iterator riter
= entries_
.rbegin();
293 riter
!= entries_
.rend();
295 if (riter
->log_level
> max_level
)
298 log_entries
.AppendString((*riter
).GetAsJSON());
301 (*riter
).ToString(show_time
, show_file
, show_desc
, format_html
);
304 if (max_events
> 0 && ++nlines
>= max_events
)
309 JSONStringValueSerializer
serializer(&result
);
310 serializer
.Serialize(log_entries
);
318 const LogLevel kDefaultLogLevel
= LOG_LEVEL_EVENT
;
321 if (g_network_event_log
)
322 delete g_network_event_log
; // reset log
323 g_network_event_log
= new NetworkEventLog();
327 delete g_network_event_log
;
328 g_network_event_log
= NULL
;
331 bool IsInitialized() { return g_network_event_log
!= NULL
; }
335 size_t GetMaxLogEntries() { return g_max_network_event_log_entries
; }
337 void SetMaxLogEntries(size_t max_entries
) {
338 g_max_network_event_log_entries
= max_entries
;
339 if (!g_network_event_log
)
341 while (g_network_event_log
->entries().size() > max_entries
)
342 g_network_event_log
->entries().pop_front();
345 void AddEntry(const char* file
,
348 const std::string
& event
,
349 const std::string
& description
) {
352 filestr
= base::FilePath(std::string(file
)).BaseName().value();
353 LogEntry
entry(filestr
, file_line
, log_level
, event
, description
);
354 if (!g_network_event_log
) {
355 entry
.SendToVLogOrErrorLog();
358 g_network_event_log
->AddLogEntry(entry
);
361 } // namespace internal
363 std::string
GetAsString(StringOrder order
,
364 const std::string
& format
,
367 if (!g_network_event_log
)
368 return "NetworkEventLog not initialized.";
369 return g_network_event_log
->GetAsString(order
, format
, max_level
, max_events
);
372 std::string
ValueAsString(const base::Value
& value
) {
374 base::JSONWriter::WriteWithOptions(
375 &value
, base::JSONWriter::OPTIONS_OMIT_BINARY_VALUES
, &vstr
);
376 return vstr
.empty() ? "''" : vstr
;
379 } // namespace network_event_log
380 } // namespace chromeos