1 // 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 
15 #include "platform/impl/logging.h"
16 #include "platform/impl/logging_test.h"
17 #include "util/trace_logging.h"
18 
19 namespace openscreen {
20 namespace {
21 
22 int g_log_fd = STDERR_FILENO;
23 LogLevel g_log_level = LogLevel::kWarning;
24 std::vector<std::string>* g_log_messages_for_test = nullptr;
25 
operator <<(std::ostream & os,const LogLevel & level)26 std::ostream& operator<<(std::ostream& os, const LogLevel& level) {
27   const char* level_string = "";
28   switch (level) {
29     case LogLevel::kVerbose:
30       level_string = "VERBOSE";
31       break;
32     case LogLevel::kInfo:
33       level_string = "INFO";
34       break;
35     case LogLevel::kWarning:
36       level_string = "WARNING";
37       break;
38     case LogLevel::kError:
39       level_string = "ERROR";
40       break;
41     case LogLevel::kFatal:
42       level_string = "FATAL";
43       break;
44   }
45   os << level_string;
46   return os;
47 }
48 
49 }  // namespace
50 
SetLogFifoOrDie(const char * filename)51 void SetLogFifoOrDie(const char* filename) {
52   if (g_log_fd != STDERR_FILENO) {
53     close(g_log_fd);
54     g_log_fd = STDERR_FILENO;
55   }
56 
57   // Note: The use of OSP_CHECK/OSP_LOG_* here will log to stderr.
58   struct stat st = {};
59   int open_result = -1;
60   if (stat(filename, &st) == -1 && errno == ENOENT) {
61     if (mkfifo(filename, 0644) == 0) {
62       open_result = open(filename, O_WRONLY);
63       OSP_CHECK_NE(open_result, -1)
64           << "open(" << filename << ") failed: " << strerror(errno);
65     } else {
66       OSP_LOG_FATAL << "mkfifo(" << filename << ") failed: " << strerror(errno);
67     }
68   } else if (S_ISFIFO(st.st_mode)) {
69     open_result = open(filename, O_WRONLY);
70     OSP_CHECK_NE(open_result, -1)
71         << "open(" << filename << ") failed: " << strerror(errno);
72   } else {
73     OSP_LOG_FATAL << "not a FIFO special file: " << filename;
74   }
75 
76   // Direct all logging to the opened FIFO file.
77   g_log_fd = open_result;
78 }
79 
SetLogLevel(LogLevel level)80 void SetLogLevel(LogLevel level) {
81   g_log_level = level;
82 }
83 
GetLogLevel()84 LogLevel GetLogLevel() {
85   return g_log_level;
86 }
87 
IsLoggingOn(LogLevel level,const char * file)88 bool IsLoggingOn(LogLevel level, const char* file) {
89   // Possible future enhancement: Use glob patterns passed on the command-line
90   // to use a different logging level for certain files, like in Chromium.
91   return level >= g_log_level;
92 }
93 
LogWithLevel(LogLevel level,const char * file,int line,std::stringstream message)94 void LogWithLevel(LogLevel level,
95                   const char* file,
96                   int line,
97                   std::stringstream message) {
98   if (level < g_log_level)
99     return;
100 
101   std::stringstream ss;
102   ss << "[" << level << ":" << file << "(" << line << "):T" << std::hex
103      << TRACE_CURRENT_ID << "] " << message.rdbuf() << '\n';
104   const auto ss_str = ss.str();
105   const auto bytes_written = write(g_log_fd, ss_str.c_str(), ss_str.size());
106   OSP_DCHECK(bytes_written);
107   if (g_log_messages_for_test) {
108     g_log_messages_for_test->push_back(ss_str);
109   }
110 }
111 
Break()112 [[noreturn]] void Break() {
113 // Generally this will just resolve to an abort anyways, but gives the
114 // compiler a chance to peform a more appropriate, target specific trap
115 // as appropriate.
116 #if defined(_DEBUG)
117   __builtin_trap();
118 #else
119   std::abort();
120 #endif
121 }
122 
SetLogBufferForTest(std::vector<std::string> * messages)123 void SetLogBufferForTest(std::vector<std::string>* messages) {
124   g_log_messages_for_test = messages;
125 }
126 
127 }  // namespace openscreen
128