blob: e666998aabb938b296aa1776583dab056bf2ed92 [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;
Yuri Wiitalab7979032019-11-08 15:17:20 -080025
26std::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
51void SetLogFifoOrDie(const char* filename) {
52 if (g_log_fd != STDERR_FILENO) {
53 close(g_log_fd);
54 g_log_fd = STDERR_FILENO;
55 }
56
mark a. foltzb0b58912020-07-09 11:48:23 -070057 // Note: The use of OSP_CHECK/OSP_LOG_* here will log to stderr.
Yuri Wiitalab7979032019-11-08 15:17:20 -080058 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
80void SetLogLevel(LogLevel level) {
81 g_log_level = level;
82}
83
mark a. foltzd6a5a222020-07-28 17:28:06 -070084LogLevel GetLogLevel() {
85 return g_log_level;
86}
87
Yuri Wiitala75ea15d2019-12-03 16:01:48 -080088bool IsLoggingOn(LogLevel level, const char* file) {
Yuri Wiitalab7979032019-11-08 15:17:20 -080089 // 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
94void LogWithLevel(LogLevel level,
Yuri Wiitala75ea15d2019-12-03 16:01:48 -080095 const char* file,
Yuri Wiitalab7979032019-11-08 15:17:20 -080096 int line,
Yuri Wiitala75ea15d2019-12-03 16:01:48 -080097 std::stringstream message) {
Yuri Wiitalab7979032019-11-08 15:17:20 -080098 if (level < g_log_level)
99 return;
100
101 std::stringstream ss;
102 ss << "[" << level << ":" << file << "(" << line << "):T" << std::hex
Yuri Wiitala75ea15d2019-12-03 16:01:48 -0800103 << TRACE_CURRENT_ID << "] " << message.rdbuf() << '\n';
Yuri Wiitalab7979032019-11-08 15:17:20 -0800104 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);
mark a. foltzd6a5a222020-07-28 17:28:06 -0700107 if (g_log_messages_for_test) {
108 g_log_messages_for_test->push_back(ss_str);
109 }
Yuri Wiitalab7979032019-11-08 15:17:20 -0800110}
111
Jordan Bayles759af7f2020-11-24 12:09:04 -0800112[[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.
Yuri Wiitalab7979032019-11-08 15:17:20 -0800116#if defined(_DEBUG)
117 __builtin_trap();
118#else
119 std::abort();
120#endif
121}
122
mark a. foltzd6a5a222020-07-28 17:28:06 -0700123void SetLogBufferForTest(std::vector<std::string>* messages) {
124 g_log_messages_for_test = messages;
125}
126
Yuri Wiitalab7979032019-11-08 15:17:20 -0800127} // namespace openscreen