summaryrefslogtreecommitdiff
path: root/src/mongo/logger/logstream_builder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/logger/logstream_builder.cpp')
-rw-r--r--src/mongo/logger/logstream_builder.cpp134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/mongo/logger/logstream_builder.cpp b/src/mongo/logger/logstream_builder.cpp
new file mode 100644
index 00000000000..8dd778fecc9
--- /dev/null
+++ b/src/mongo/logger/logstream_builder.cpp
@@ -0,0 +1,134 @@
+/* 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/logger/logstream_builder.h"
+
+#include "mongo/base/init.h"
+#include "mongo/base/owned_pointer_vector.h"
+#include "mongo/base/status.h"
+#include "mongo/logger/message_event_utf8_encoder.h"
+#include "mongo/logger/tee.h"
+#include "mongo/util/assert_util.h" // TODO: remove apple dep for this in threadlocal.h
+#include "mongo/util/concurrency/threadlocal.h"
+#include "mongo/util/time_support.h"
+
+namespace mongo {
+
+namespace {
+
+ /// Type of per-thread cache for storing pre-constructed ostringstreams. While its type is
+ /// vector, it should only ever contain 0 or 1 item. It is a vector rather than just a
+ /// thread_specific_ptr<> because of the high cost of thread_specific_ptr<>::reset().
+ typedef OwnedPointerVector<std::ostringstream> OwnedOstreamVector;
+
+ /// This flag indicates whether the system providing a per-thread cache of ostringstreams
+ /// for use by LogstreamBuilder instances is initialized and ready for use. Until this
+ /// flag is true, LogstreamBuilder instances must not use the cache.
+ bool isThreadOstreamCacheInitialized = false;
+
+ MONGO_INITIALIZER(LogstreamBuilder)(InitializerContext*) {
+ isThreadOstreamCacheInitialized = true;
+ return Status::OK();
+ }
+
+} // namespace
+
+ TSP_DECLARE(OwnedOstreamVector, threadOstreamCache);
+ TSP_DEFINE(OwnedOstreamVector, threadOstreamCache);
+
+namespace logger {
+
+ LogstreamBuilder::LogstreamBuilder(MessageLogDomain* domain,
+ const std::string& contextName,
+ LogSeverity severity)
+ : _domain(domain),
+ _contextName(contextName),
+ _severity(severity),
+ _os(NULL),
+ _tee(NULL) {
+ }
+
+ LogstreamBuilder::LogstreamBuilder(logger::MessageLogDomain* domain,
+ const std::string& contextName,
+ LabeledLevel labeledLevel)
+ : _domain(domain),
+ _contextName(contextName),
+ _severity(labeledLevel),
+ _os(NULL),
+ _tee(NULL) {
+
+ setBaseMessage(labeledLevel.getLabel());
+ }
+
+ LogstreamBuilder::LogstreamBuilder(const LogstreamBuilder& other)
+ : _domain(other._domain),
+ _contextName(other._contextName),
+ _severity(other._severity),
+ _baseMessage(other._baseMessage),
+ _os(NULL),
+ _tee(NULL) {
+
+ if (other._os || other._tee)
+ abort();
+ }
+
+
+ LogstreamBuilder::~LogstreamBuilder() {
+ if (_os) {
+ if ( !_baseMessage.empty() ) _baseMessage.push_back(' ');
+ _baseMessage += _os->str();
+ MessageEventEphemeral message(curTimeMillis64(), _severity, _contextName, _baseMessage);
+ _domain->append(message);
+ if (_tee) {
+ _os->str("");
+ logger::MessageEventDetailsEncoder teeEncoder;
+ teeEncoder.encode(message, *_os);
+ _tee->write(_os->str());
+ }
+ _os->str("");
+ if (isThreadOstreamCacheInitialized && threadOstreamCache.getMake()->vector().empty()) {
+ threadOstreamCache.get()->mutableVector().push_back(_os);
+ }
+ else {
+ delete _os;
+ }
+ }
+ }
+
+ void LogstreamBuilder::operator<<(Tee* tee) {
+ makeStream(); // Adding a Tee counts for purposes of deciding to make a log message.
+ // TODO: dassert(!_tee);
+ _tee = tee;
+ }
+
+ void LogstreamBuilder::makeStream() {
+ if (!_os) {
+ if (isThreadOstreamCacheInitialized &&
+ !threadOstreamCache.getMake()->vector().empty()) {
+
+ std::vector<std::ostringstream*>& oses = threadOstreamCache.get()->mutableVector();
+ _os = oses.back();
+ oses.pop_back();
+ }
+ else {
+ _os = new std::ostringstream;
+ }
+ }
+ }
+
+} // namespace logger
+} // namespace mongo