blob: 6e9564c95253feb5b92a425b8803be9309c2398a [file] [log] [blame]
Yuri Wiitalab7979032019-11-08 15:17:20 -08001// Copyright 2019 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.
4
5#include <errno.h>
6#include <fcntl.h>
7#include <sys/stat.h>
8#include <sys/types.h>
9#include <unistd.h>
10
11#include <cstdlib>
12#include <iostream>
13#include <sstream>
14
Yuri Wiitalab7979032019-11-08 15:17:20 -080015#include "platform/impl/logging.h"
mark a. foltzd6a5a222020-07-28 17:28:06 -070016#include "platform/impl/logging_test.h"
Yuri Wiitala8e6db3b2019-11-20 11:20:54 -080017#include "util/trace_logging.h"
Yuri Wiitalab7979032019-11-08 15:17:20 -080018
19namespace openscreen {
Yuri Wiitalab7979032019-11-08 15:17:20 -080020namespace {
21
22int g_log_fd = STDERR_FILENO;
23LogLevel g_log_level = LogLevel::kWarning;
mark a. foltzd6a5a222020-07-28 17:28:06 -070024std::vector<std::string>* g_log_messages_for_test = nullptr;
25bool* g_break_was_called_for_test = nullptr;
Yuri Wiitalab7979032019-11-08 15:17:20 -080026
27std::ostream& operator<<(std::ostream& os, const LogLevel& level) {
28 const char* level_string = "";
29 switch (level) {
30 case LogLevel::kVerbose:
31 level_string = "VERBOSE";
32 break;
33 case LogLevel::kInfo:
34 level_string = "INFO";
35 break;
36 case LogLevel::kWarning:
37 level_string = "WARNING";
38 break;
39 case LogLevel::kError:
40 level_string = "ERROR";
41 break;
42 case LogLevel::kFatal:
43 level_string = "FATAL";
44 break;
45 }
46 os << level_string;
47 return os;
48}
49
50} // namespace
51
52void SetLogFifoOrDie(const char* filename) {
53 if (g_log_fd != STDERR_FILENO) {
54 close(g_log_fd);
55 g_log_fd = STDERR_FILENO;
56 }
57
mark a. foltzb0b58912020-07-09 11:48:23 -070058 // Note: The use of OSP_CHECK/OSP_LOG_* here will log to stderr.
Yuri Wiitalab7979032019-11-08 15:17:20 -080059 struct stat st = {};
60 int open_result = -1;
61 if (stat(filename, &st) == -1 && errno == ENOENT) {
62 if (mkfifo(filename, 0644) == 0) {
63 open_result = open(filename, O_WRONLY);
64 OSP_CHECK_NE(open_result, -1)
65 << "open(" << filename << ") failed: " << strerror(errno);
66 } else {
67 OSP_LOG_FATAL << "mkfifo(" << filename << ") failed: " << strerror(errno);
68 }
69 } else if (S_ISFIFO(st.st_mode)) {
70 open_result = open(filename, O_WRONLY);
71 OSP_CHECK_NE(open_result, -1)
72 << "open(" << filename << ") failed: " << strerror(errno);
73 } else {
74 OSP_LOG_FATAL << "not a FIFO special file: " << filename;
75 }
76
77 // Direct all logging to the opened FIFO file.
78 g_log_fd = open_result;
79}
80
81void SetLogLevel(LogLevel level) {
82 g_log_level = level;
83}
84
mark a. foltzd6a5a222020-07-28 17:28:06 -070085LogLevel GetLogLevel() {
86 return g_log_level;
87}
88
Yuri Wiitala75ea15d2019-12-03 16:01:48 -080089bool IsLoggingOn(LogLevel level, const char* file) {
Yuri Wiitalab7979032019-11-08 15:17:20 -080090 // Possible future enhancement: Use glob patterns passed on the command-line
91 // to use a different logging level for certain files, like in Chromium.
92 return level >= g_log_level;
93}
94
95void LogWithLevel(LogLevel level,
Yuri Wiitala75ea15d2019-12-03 16:01:48 -080096 const char* file,
Yuri Wiitalab7979032019-11-08 15:17:20 -080097 int line,
Yuri Wiitala75ea15d2019-12-03 16:01:48 -080098 std::stringstream message) {
Yuri Wiitalab7979032019-11-08 15:17:20 -080099 if (level < g_log_level)
100 return;
101
102 std::stringstream ss;
103 ss << "[" << level << ":" << file << "(" << line << "):T" << std::hex
Yuri Wiitala75ea15d2019-12-03 16:01:48 -0800104 << TRACE_CURRENT_ID << "] " << message.rdbuf() << '\n';
Yuri Wiitalab7979032019-11-08 15:17:20 -0800105 const auto ss_str = ss.str();
106 const auto bytes_written = write(g_log_fd, ss_str.c_str(), ss_str.size());
107 OSP_DCHECK(bytes_written);
mark a. foltzd6a5a222020-07-28 17:28:06 -0700108 if (g_log_messages_for_test) {
109 g_log_messages_for_test->push_back(ss_str);
110 }
Yuri Wiitalab7979032019-11-08 15:17:20 -0800111}
112
113void Break() {
mark a. foltzd6a5a222020-07-28 17:28:06 -0700114 if (g_break_was_called_for_test) {
115 *g_break_was_called_for_test = true;
116 return;
117 }
Yuri Wiitalab7979032019-11-08 15:17:20 -0800118#if defined(_DEBUG)
119 __builtin_trap();
120#else
121 std::abort();
122#endif
123}
124
mark a. foltzd6a5a222020-07-28 17:28:06 -0700125void SetLogBufferForTest(std::vector<std::string>* messages) {
126 g_log_messages_for_test = messages;
127}
128
129void DisableBreakForTest(bool* break_was_called) {
130 g_break_was_called_for_test = break_was_called;
131}
132
Yuri Wiitalab7979032019-11-08 15:17:20 -0800133} // namespace openscreen