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