Skip to content

Commit cc1379e

Browse files
committed
Add tee file for logging
1 parent 58d4e95 commit cc1379e

File tree

3 files changed

+37
-4
lines changed

3 files changed

+37
-4
lines changed

toolbelt/logging.cc

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2023 David Allison
1+
// Copyright 2023,2025 David Allison
22
// All Rights Reserved
33
// See LICENSE file for licensing information.
44

@@ -132,11 +132,26 @@ void Logger::Log(LogLevel level, const char *fmt, ...) {
132132
va_end(ap);
133133
}
134134

135+
absl::Status Logger::SetTeeFile(const std::string &filename, bool truncate) {
136+
if (tee_stream_ != nullptr) {
137+
fclose(tee_stream_);
138+
}
139+
tee_stream_ = fopen(filename.c_str(), truncate ? "w" : "a");
140+
if (tee_stream_ == nullptr) {
141+
return absl::InternalError(absl::StrFormat("Failed to open tee file %s: %s",
142+
filename, strerror(errno)));
143+
}
144+
return absl::OkStatus();
145+
}
146+
135147
void Logger::VLog(LogLevel level, const char *fmt, va_list ap) {
136148
if (level < min_level_) {
137149
return;
138150
}
151+
#pragma clang diagnostic push
152+
#pragma clang diagnostic ignored "-Wformat-nonliteral"
139153
size_t n = vsnprintf(buffer_, sizeof(buffer_), fmt, ap);
154+
#pragma clang diagnostic pop
140155

141156
// Strip final \n if present. Refactoring from printf can leave
142157
// this in place.
@@ -196,6 +211,11 @@ void Logger::Log(LogLevel level, uint64_t timestamp, const std::string &source,
196211
break;
197212
}
198213

214+
if (tee_stream_ != nullptr) {
215+
fprintf(tee_stream_, "%s %s: %s: %s: %s\n", timebuf, subsystem_.c_str(),
216+
LogLevelAsString(level), source.c_str(), text.c_str());
217+
fflush(tee_stream_);
218+
}
199219
if (level == LogLevel::kFatal) {
200220
abort();
201221
}
@@ -311,7 +331,9 @@ void Logger::LogColumnar(const char *timebuf, LogLevel level,
311331
// clang-format off.
312332
fprintf(output_stream_, "%-*s%s%-*s%s\n", prefix_length,
313333
first_line ? prefix.c_str() : "",
314-
color::SetColor(ColorForLogLevel(level)).c_str(), int(column_widths_[4]), segment.c_str(), color::ResetColor().c_str());
334+
color::SetColor(ColorForLogLevel(level)).c_str(),
335+
int(column_widths_[4]), segment.c_str(),
336+
color::ResetColor().c_str());
315337
// clang-format on
316338
start += segment.size();
317339
if (start >= text.size()) {

toolbelt/logging.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// Copyright 2023 David Allison
1+
// Copyright 2023,2025 David Allison
22
// All Rights Reserved
33
// See LICENSE file for licensing information.
44

55
#ifndef __TOOLBELT_LOGGING_H
66
#define __TOOLBELT_LOGGING_H
77

8+
#include "absl/status/status.h"
89
#include "toolbelt/color.h"
910
#include <stdarg.h>
1011
#include <string>
@@ -59,6 +60,16 @@ class Logger {
5960
void Enable() { enabled_ = true; }
6061
void Disable() { enabled_ = false; }
6162

63+
// We can also tee the output to a file or a stream. Calling this more than
64+
// once will close the current stream and open a new one.
65+
absl::Status SetTeeFile(const std::string& filename, bool truncate = true);
66+
void SetTeeStream(FILE *stream) {
67+
if (tee_stream_ != nullptr) {
68+
fclose(tee_stream_);
69+
}
70+
tee_stream_ = stream;
71+
}
72+
6273
// Log a message at the given log level. If standard error is a TTY
6374
// it will be in color.
6475
virtual void Log(LogLevel level, const char *fmt, ...);
@@ -125,6 +136,7 @@ class Logger {
125136
int screen_width_;
126137
LogTheme theme_ = LogTheme::kDefault;
127138

139+
FILE* tee_stream_ = nullptr;
128140
static constexpr int kNumColumns = 5;
129141
size_t column_widths_[kNumColumns];
130142
color::Color colors_[kNumColumns];

toolbelt/sockets.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,6 @@ absl::StatusOr<ssize_t> Socket::SendMessage(char *buffer, size_t length,
262262
// the address passed as the buffer.
263263
int32_t *lengthptr = reinterpret_cast<int32_t *>(buffer) - 1;
264264
*lengthptr = htonl(length);
265-
266265
ssize_t n = SendFully(c, fd_.Fd(), reinterpret_cast<char *>(lengthptr),
267266
length + sizeof(int32_t), IsBlocking());
268267
if (n == -1) {

0 commit comments

Comments
 (0)