1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
/* Copyright 2013 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mongo/platform/basic.h"
#include "mongo/tools/tool_logger.h"
#include <iostream>
#include "mongo/base/init.h"
#include "mongo/logger/console_appender.h"
#include "mongo/logger/log_manager.h"
#include "mongo/logger/logger.h"
#include "mongo/logger/message_event.h"
#include "mongo/logger/message_event_utf8_encoder.h"
#include "mongo/tools/tool_options.h"
#include "mongo/util/log.h"
namespace mongo {
namespace {
/*
* Theory of operation:
*
* At process start, the loader initializes "consoleMutex" to NULL. At some point during static
* initialization, the static initialization process, running in the one and only extant thread,
* allocates a new boost::mutex on the heap and assigns consoleMutex to point to it. While
* consoleMutex is still NULL, we know that there is only one thread extant, so it is safe to
* skip locking the consoleMutex in the ErrorConsole constructor. Once the mutex is initialized,
* users of ErrorConsole can start acquiring it.
*/
boost::mutex *consoleMutex = new boost::mutex;
} // namespace
ErrorConsole::ErrorConsole() : _consoleLock() {
if (consoleMutex) {
boost::unique_lock<boost::mutex> lk(*consoleMutex);
lk.swap(_consoleLock);
}
}
std::ostream& ErrorConsole::out() { return std::cerr; }
namespace {
logger::MessageLogDomain* toolErrorOutput = NULL;
logger::MessageLogDomain* toolNonErrorOutput = NULL;
logger::MessageLogDomain* toolNonErrorDecoratedOutput = NULL;
} // namespace
MONGO_INITIALIZER_GENERAL(ToolLogRedirection,
("GlobalLogManager", "EndStartupOptionHandling"),
("default"))(InitializerContext*) {
using logger::MessageEventEphemeral;
using logger::MessageEventDetailsEncoder;
using logger::MessageLogDomain;
using logger::ConsoleAppender;
toolErrorOutput = logger::globalLogManager()->getNamedDomain("toolErrorOutput");
toolNonErrorOutput = logger::globalLogManager()->getNamedDomain("toolNonErrorOutput");
toolNonErrorDecoratedOutput =
logger::globalLogManager()->getNamedDomain("toolNonErrorDecoratedOutput");
// Errors in the tools always go to stderr
toolErrorOutput->attachAppender(
MessageLogDomain::AppenderAutoPtr(
new ConsoleAppender<MessageEventEphemeral, ErrorConsole>(
new logger::MessageEventUnadornedEncoder)));
// If we are outputting data to stdout, we may need to redirect all logging to stderr
if (!toolGlobalParams.canUseStdout) {
logger::globalLogDomain()->clearAppenders();
logger::globalLogDomain()->attachAppender(MessageLogDomain::AppenderAutoPtr(
new ConsoleAppender<MessageEventEphemeral, ErrorConsole>(
new MessageEventDetailsEncoder)));
}
// Only put an appender on our informational messages if we did not use --quiet
if (!toolGlobalParams.quiet) {
if (toolGlobalParams.canUseStdout) {
// If we can use stdout, we can use the ConsoleAppender with the default console
toolNonErrorOutput->attachAppender(
MessageLogDomain::AppenderAutoPtr(
new ConsoleAppender<MessageEventEphemeral>(
new logger::MessageEventUnadornedEncoder)));
toolNonErrorDecoratedOutput->attachAppender(
MessageLogDomain::AppenderAutoPtr(
new ConsoleAppender<MessageEventEphemeral>(
new logger::MessageEventDetailsEncoder)));
}
else {
// If we cannot use stdout, we have to use ErrorConsole to redirect informational
// messages to stderr
toolNonErrorOutput->attachAppender(
MessageLogDomain::AppenderAutoPtr(
new ConsoleAppender<MessageEventEphemeral, ErrorConsole>(
new logger::MessageEventUnadornedEncoder)));
toolNonErrorDecoratedOutput->attachAppender(
MessageLogDomain::AppenderAutoPtr(
new ConsoleAppender<MessageEventEphemeral, ErrorConsole>(
new logger::MessageEventDetailsEncoder)));
}
}
return Status::OK();
}
LogstreamBuilder toolInfoLog() {
return LogstreamBuilder(toolNonErrorDecoratedOutput,
"",
logger::LogSeverity::Log());
}
LogstreamBuilder toolInfoOutput() {
return LogstreamBuilder(toolNonErrorOutput,
"",
logger::LogSeverity::Log());
}
LogstreamBuilder toolError() {
return LogstreamBuilder(toolErrorOutput,
"",
logger::LogSeverity::Log());
}
} // namespace mongo
|