Skip to content

Commit 7aff03a

Browse files
author
Xin Liu
committed
8267517: async logging for stdout and stderr
Reviewed-by: dholmes, ysuenaga
1 parent ff2ca4f commit 7aff03a

File tree

7 files changed

+118
-37
lines changed

7 files changed

+118
-37
lines changed

src/hotspot/share/logging/logAsyncWriter.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "logging/logAsyncWriter.hpp"
2626
#include "logging/logConfiguration.hpp"
2727
#include "logging/logFileOutput.hpp"
28+
#include "logging/logFileStreamOutput.hpp"
2829
#include "logging/logHandle.hpp"
2930
#include "runtime/atomic.hpp"
3031
#include "runtime/os.inline.hpp"
@@ -56,7 +57,7 @@ void AsyncLogWriter::enqueue_locked(const AsyncLogMessage& msg) {
5657
_lock.notify();
5758
}
5859

59-
void AsyncLogWriter::enqueue(LogFileOutput& output, const LogDecorations& decorations, const char* msg) {
60+
void AsyncLogWriter::enqueue(LogFileStreamOutput& output, const LogDecorations& decorations, const char* msg) {
6061
AsyncLogMessage m(&output, decorations, os::strdup(msg));
6162

6263
{ // critical area
@@ -67,7 +68,7 @@ void AsyncLogWriter::enqueue(LogFileOutput& output, const LogDecorations& decora
6768

6869
// LogMessageBuffer consists of a multiple-part/multiple-line messsage.
6970
// The lock here guarantees its integrity.
70-
void AsyncLogWriter::enqueue(LogFileOutput& output, LogMessageBuffer::Iterator msg_iterator) {
71+
void AsyncLogWriter::enqueue(LogFileStreamOutput& output, LogMessageBuffer::Iterator msg_iterator) {
7172
AsyncLogLocker locker;
7273

7374
for (; !msg_iterator.is_at_end(); msg_iterator++) {
@@ -95,7 +96,7 @@ class AsyncLogMapIterator {
9596

9697
public:
9798
AsyncLogMapIterator(AsyncLogBuffer& logs) :_logs(logs) {}
98-
bool do_entry(LogFileOutput* output, uint32_t& counter) {
99+
bool do_entry(LogFileStreamOutput* output, uint32_t& counter) {
99100
using none = LogTagSetMapping<LogTag::__NO_TAG>;
100101

101102
if (counter > 0) {

src/hotspot/share/logging/logAsyncWriter.hpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
#define SHARE_LOGGING_LOGASYNCWRITER_HPP
2626
#include "logging/log.hpp"
2727
#include "logging/logDecorations.hpp"
28-
#include "logging/logFileOutput.hpp"
2928
#include "logging/logMessageBuffer.hpp"
3029
#include "memory/resourceArea.hpp"
3130
#include "runtime/nonJavaThread.hpp"
31+
#include "runtime/semaphore.hpp"
3232
#include "utilities/resourceHash.hpp"
3333
#include "utilities/linkedlist.hpp"
3434

@@ -90,25 +90,28 @@ class LinkedListDeque : private LinkedListImpl<E, ResourceObj::C_HEAP, F> {
9090
}
9191
};
9292

93+
// Forward declaration
94+
class LogFileStreamOutput;
95+
9396
class AsyncLogMessage {
94-
LogFileOutput* _output;
97+
LogFileStreamOutput* _output;
9598
const LogDecorations _decorations;
9699
char* _message;
97100

98101
public:
99-
AsyncLogMessage(LogFileOutput* output, const LogDecorations& decorations, char* msg)
102+
AsyncLogMessage(LogFileStreamOutput* output, const LogDecorations& decorations, char* msg)
100103
: _output(output), _decorations(decorations), _message(msg) {}
101104

102105
// placeholder for LinkedListImpl.
103106
bool equals(const AsyncLogMessage& o) const { return false; }
104107

105-
LogFileOutput* output() const { return _output; }
108+
LogFileStreamOutput* output() const { return _output; }
106109
const LogDecorations& decorations() const { return _decorations; }
107110
char* message() const { return _message; }
108111
};
109112

110113
typedef LinkedListDeque<AsyncLogMessage, mtLogging> AsyncLogBuffer;
111-
typedef ResourceHashtable<LogFileOutput*,
114+
typedef ResourceHashtable<LogFileStreamOutput*,
112115
uint32_t,
113116
17, /*table_size*/
114117
ResourceObj::C_HEAP,
@@ -168,8 +171,8 @@ class AsyncLogWriter : public NonJavaThread {
168171
}
169172

170173
public:
171-
void enqueue(LogFileOutput& output, const LogDecorations& decorations, const char* msg);
172-
void enqueue(LogFileOutput& output, LogMessageBuffer::Iterator msg_iterator);
174+
void enqueue(LogFileStreamOutput& output, const LogDecorations& decorations, const char* msg);
175+
void enqueue(LogFileStreamOutput& output, LogMessageBuffer::Iterator msg_iterator);
173176

174177
static AsyncLogWriter* instance();
175178
static void initialize();

src/hotspot/share/logging/logFileOutput.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,9 @@ int LogFileOutput::write_blocking(const LogDecorations& decorations, const char*
272272
return 0;
273273
}
274274

275-
int written = LogFileStreamOutput::write(decorations, msg);
275+
int written = write_internal(decorations, msg);
276+
// Need to flush to the filesystem before should_rotate()
277+
written = flush() ? written : -1;
276278
if (written > 0) {
277279
_current_size += written;
278280

src/hotspot/share/logging/logFileOutput.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class LogFileOutput : public LogFileStreamOutput {
8585
virtual bool set_option(const char* key, const char* value, outputStream* errstream);
8686
virtual int write(const LogDecorations& decorations, const char* msg);
8787
virtual int write(LogMessageBuffer::Iterator msg_iterator);
88-
int write_blocking(const LogDecorations& decorations, const char* msg);
88+
virtual int write_blocking(const LogDecorations& decorations, const char* msg);
8989
virtual void force_rotate();
9090
virtual void describe(outputStream* out);
9191

src/hotspot/share/logging/logFileStreamOutput.cpp

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
*/
2424
#include "precompiled.hpp"
2525
#include "jvm.h"
26+
#include "logging/logAsyncWriter.hpp"
2627
#include "logging/logDecorators.hpp"
2728
#include "logging/logDecorations.hpp"
2829
#include "logging/logFileStreamOutput.hpp"
@@ -135,8 +136,15 @@ bool LogFileStreamOutput::flush() {
135136
total += result; \
136137
}
137138

138-
int LogFileStreamOutput::write_internal(const char* msg) {
139+
int LogFileStreamOutput::write_internal(const LogDecorations& decorations, const char* msg) {
139140
int written = 0;
141+
const bool use_decorations = !_decorators.is_empty();
142+
143+
if (use_decorations) {
144+
WRITE_LOG_WITH_RESULT_CHECK(write_decorations(decorations), written);
145+
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, " "), written);
146+
}
147+
140148
if (!_fold_multilines) {
141149
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", msg), written);
142150
} else {
@@ -159,31 +167,35 @@ int LogFileStreamOutput::write_internal(const char* msg) {
159167
return written;
160168
}
161169

170+
int LogFileStreamOutput::write_blocking(const LogDecorations& decorations, const char* msg) {
171+
int written = write_internal(decorations, msg);
172+
return flush() ? written : -1;
173+
}
174+
162175
int LogFileStreamOutput::write(const LogDecorations& decorations, const char* msg) {
163-
const bool use_decorations = !_decorators.is_empty();
176+
AsyncLogWriter* aio_writer = AsyncLogWriter::instance();
177+
if (aio_writer != nullptr) {
178+
aio_writer->enqueue(*this, decorations, msg);
179+
return 0;
180+
}
164181

165-
int written = 0;
166182
FileLocker flocker(_stream);
167-
if (use_decorations) {
168-
WRITE_LOG_WITH_RESULT_CHECK(write_decorations(decorations), written);
169-
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, " "), written);
170-
}
171-
written += write_internal(msg);
183+
int written = write_internal(decorations, msg);
172184

173185
return flush() ? written : -1;
174186
}
175187

176188
int LogFileStreamOutput::write(LogMessageBuffer::Iterator msg_iterator) {
177-
const bool use_decorations = !_decorators.is_empty();
189+
AsyncLogWriter* aio_writer = AsyncLogWriter::instance();
190+
if (aio_writer != nullptr) {
191+
aio_writer->enqueue(*this, msg_iterator);
192+
return 0;
193+
}
178194

179195
int written = 0;
180196
FileLocker flocker(_stream);
181197
for (; !msg_iterator.is_at_end(); msg_iterator++) {
182-
if (use_decorations) {
183-
WRITE_LOG_WITH_RESULT_CHECK(write_decorations(msg_iterator.decorations()), written);
184-
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, " "), written);
185-
}
186-
written += write_internal(msg_iterator.message());
198+
written += write_internal(msg_iterator.decorations(), msg_iterator.message());
187199
}
188200

189201
return flush() ? written : -1;

src/hotspot/share/logging/logFileStreamOutput.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ class LogFileStreamOutput : public LogOutput {
4646
bool _fold_multilines;
4747
bool _write_error_is_shown;
4848

49-
int write_internal(const char* msg);
5049
protected:
5150
FILE* _stream;
5251
size_t _decorator_padding[LogDecorators::Count];
@@ -58,12 +57,15 @@ class LogFileStreamOutput : public LogOutput {
5857
}
5958

6059
int write_decorations(const LogDecorations& decorations);
60+
int write_internal(const LogDecorations& decorations, const char* msg);
6161
bool flush();
6262

6363
public:
6464
virtual bool set_option(const char* key, const char* value, outputStream* errstream);
6565
virtual int write(const LogDecorations& decorations, const char* msg);
6666
virtual int write(LogMessageBuffer::Iterator msg_iterator);
67+
// Write API used by AsyncLogWriter
68+
virtual int write_blocking(const LogDecorations& decorations, const char* msg);
6769
virtual void describe(outputStream* out);
6870
};
6971

test/hotspot/gtest/logging/test_asynclog.cpp

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,38 @@ LOG_LEVEL_LIST
6666
log_trace(logging)("log_trace-test");
6767
log_debug(logging)("log_debug-test");
6868
}
69+
70+
void test_asynclog_drop_messages() {
71+
if (AsyncLogWriter::instance() != nullptr) {
72+
const size_t sz = 100;
73+
74+
// shrink async buffer.
75+
AutoModifyRestore<size_t> saver(AsyncLogBufferSize, sz * 1024 /*in byte*/);
76+
LogMessage(logging) lm;
77+
78+
// write 100x more messages than its capacity in burst
79+
for (size_t i = 0; i < sz * 100; ++i) {
80+
lm.debug("a lot of log...");
81+
}
82+
lm.flush();
83+
}
84+
}
85+
86+
// stdout/stderr support
87+
bool write_to_file(const std::string& output) {
88+
FILE* f = fopen(TestLogFileName, "w");
89+
90+
if (f != NULL) {
91+
size_t sz = output.size();
92+
size_t written = fwrite(output.c_str(), sizeof(char), output.size(), f);
93+
94+
if (written == sz * sizeof(char)) {
95+
return fclose(f) == 0;
96+
}
97+
}
98+
99+
return false;
100+
}
69101
};
70102

71103
TEST_VM(AsyncLogBufferTest, fifo) {
@@ -198,19 +230,48 @@ TEST_VM_F(AsyncLogTest, logMessage) {
198230

199231
TEST_VM_F(AsyncLogTest, droppingMessage) {
200232
set_log_config(TestLogFileName, "logging=debug");
201-
const size_t sz = 100;
233+
test_asynclog_drop_messages();
202234

235+
AsyncLogWriter::flush();
203236
if (AsyncLogWriter::instance() != nullptr) {
204-
// shrink async buffer.
205-
AutoModifyRestore<size_t> saver(AsyncLogBufferSize, sz * 1024 /*in byte*/);
206-
LogMessage(logging) lm;
237+
EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging"));
238+
}
239+
}
207240

208-
// write 100x more messages than its capacity in burst
209-
for (size_t i = 0; i < sz * 100; ++i) {
210-
lm.debug("a lot of log...");
211-
}
212-
lm.flush();
213-
AsyncLogWriter::flush();
241+
TEST_VM_F(AsyncLogTest, stdoutOutput) {
242+
testing::internal::CaptureStdout();
243+
set_log_config("stdout", "logging=debug");
244+
245+
test_asynclog_ls();
246+
test_asynclog_drop_messages();
247+
248+
AsyncLogWriter::flush();
249+
EXPECT_TRUE(write_to_file(testing::internal::GetCapturedStdout()));
250+
251+
EXPECT_TRUE(file_contains_substring(TestLogFileName, "LogStreamWithAsyncLogImpl"));
252+
EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream msg1-msg2-msg3"));
253+
EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream newline"));
254+
255+
if (AsyncLogWriter::instance() != nullptr) {
256+
EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging"));
257+
}
258+
}
259+
260+
TEST_VM_F(AsyncLogTest, stderrOutput) {
261+
testing::internal::CaptureStderr();
262+
set_log_config("stderr", "logging=debug");
263+
264+
test_asynclog_ls();
265+
test_asynclog_drop_messages();
266+
267+
AsyncLogWriter::flush();
268+
EXPECT_TRUE(write_to_file(testing::internal::GetCapturedStderr()));
269+
270+
EXPECT_TRUE(file_contains_substring(TestLogFileName, "LogStreamWithAsyncLogImpl"));
271+
EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream msg1-msg2-msg3"));
272+
EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream newline"));
273+
274+
if (AsyncLogWriter::instance() != nullptr) {
214275
EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging"));
215276
}
216277
}

0 commit comments

Comments
 (0)