Skip to content

Commit e61bb2e

Browse files
Xin Liushipilev
authored andcommitted
8267517: async logging for stdout and stderr
Reviewed-by: shade Backport-of: 7aff03aee1a5cd70638d8bbafeb7765bc7beea45
1 parent 9288072 commit e61bb2e

File tree

7 files changed

+119
-31
lines changed

7 files changed

+119
-31
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/hashtable.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 KVHashtable<LogFileOutput*, uint32_t, mtLogging> AsyncLogMap;
114+
typedef KVHashtable<LogFileStreamOutput*, uint32_t, mtLogging> AsyncLogMap;
112115

113116
//
114117
// ASYNC LOGGING SUPPORT
@@ -163,8 +166,8 @@ class AsyncLogWriter : public NonJavaThread {
163166
}
164167

165168
public:
166-
void enqueue(LogFileOutput& output, const LogDecorations& decorations, const char* msg);
167-
void enqueue(LogFileOutput& output, LogMessageBuffer::Iterator msg_iterator);
169+
void enqueue(LogFileStreamOutput& output, const LogDecorations& decorations, const char* msg);
170+
void enqueue(LogFileStreamOutput& output, LogMessageBuffer::Iterator msg_iterator);
168171

169172
static AsyncLogWriter* instance();
170173
static void initialize();

src/hotspot/share/logging/logFileOutput.cpp

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

308-
int written = LogFileStreamOutput::write(decorations, msg);
308+
int written = write_internal(decorations, msg);
309+
// Need to flush to the filesystem before should_rotate()
310+
written = flush() ? written : -1;
309311
if (written > 0) {
310312
_current_size += written;
311313

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 initialize(const char* options, 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 & 9 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"
@@ -117,31 +118,47 @@ bool LogFileStreamOutput::flush() {
117118
total += result; \
118119
}
119120

120-
int LogFileStreamOutput::write(const LogDecorations& decorations, const char* msg) {
121+
int LogFileStreamOutput::write_internal(const LogDecorations& decorations, const char* msg) {
122+
int written = 0;
121123
const bool use_decorations = !_decorators.is_empty();
122124

123-
int written = 0;
124-
FileLocker flocker(_stream);
125125
if (use_decorations) {
126126
WRITE_LOG_WITH_RESULT_CHECK(write_decorations(decorations), written);
127127
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, " "), written);
128128
}
129129
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", msg), written);
130+
return written;
131+
}
132+
133+
int LogFileStreamOutput::write_blocking(const LogDecorations& decorations, const char* msg) {
134+
int written = write_internal(decorations, msg);
135+
return flush() ? written : -1;
136+
}
137+
138+
int LogFileStreamOutput::write(const LogDecorations& decorations, const char* msg) {
139+
AsyncLogWriter* aio_writer = AsyncLogWriter::instance();
140+
if (aio_writer != nullptr) {
141+
aio_writer->enqueue(*this, decorations, msg);
142+
return 0;
143+
}
144+
145+
FileLocker flocker(_stream);
146+
int written = write_internal(decorations, msg);
130147

131148
return flush() ? written : -1;
132149
}
133150

134151
int LogFileStreamOutput::write(LogMessageBuffer::Iterator msg_iterator) {
135-
const bool use_decorations = !_decorators.is_empty();
152+
AsyncLogWriter* aio_writer = AsyncLogWriter::instance();
153+
if (aio_writer != nullptr) {
154+
aio_writer->enqueue(*this, msg_iterator);
155+
return 0;
156+
}
136157

137158
int written = 0;
138159
FileLocker flocker(_stream);
139160
for (; !msg_iterator.is_at_end(); msg_iterator++) {
140-
if (use_decorations) {
141-
WRITE_LOG_WITH_RESULT_CHECK(write_decorations(msg_iterator.decorations()), written);
142-
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, " "), written);
143-
}
144-
WRITE_LOG_WITH_RESULT_CHECK(jio_fprintf(_stream, "%s\n", msg_iterator.message()), written);
161+
written += write_internal(msg_iterator.decorations(), msg_iterator.message());
145162
}
146163

147164
return flush() ? written : -1;

src/hotspot/share/logging/logFileStreamOutput.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ static LogFileStreamInitializer log_stream_initializer;
4242
class LogFileStreamOutput : public LogOutput {
4343
private:
4444
bool _write_error_is_shown;
45+
4546
protected:
4647
FILE* _stream;
4748
size_t _decorator_padding[LogDecorators::Count];
@@ -53,11 +54,14 @@ class LogFileStreamOutput : public LogOutput {
5354
}
5455

5556
int write_decorations(const LogDecorations& decorations);
57+
int write_internal(const LogDecorations& decorations, const char* msg);
5658
bool flush();
5759

5860
public:
5961
virtual int write(const LogDecorations& decorations, const char* msg);
6062
virtual int write(LogMessageBuffer::Iterator msg_iterator);
63+
// Write API used by AsyncLogWriter
64+
virtual int write_blocking(const LogDecorations& decorations, const char* msg);
6165
};
6266

6367
class LogStdoutOutput : public LogFileStreamOutput {

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)