Index: mojo/services/flog/cpp/flog.h |
diff --git a/mojo/services/flog/cpp/flog.h b/mojo/services/flog/cpp/flog.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5badda1b473a3d024c2cd09fdd69c0985d059228 |
--- /dev/null |
+++ b/mojo/services/flog/cpp/flog.h |
@@ -0,0 +1,197 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef MOJO_SERVICES_FLOG_CPP_FLOG_H_ |
+#define MOJO_SERVICES_FLOG_CPP_FLOG_H_ |
+ |
+#include <atomic> |
+#include <memory> |
+ |
+#include "mojo/public/cpp/application/application_impl.h" |
+#include "mojo/public/cpp/application/connect.h" |
+#include "mojo/public/cpp/bindings/array.h" |
+#include "mojo/public/cpp/bindings/message.h" |
+#include "mojo/public/cpp/environment/logging.h" |
+#include "mojo/public/cpp/system/time.h" |
+#include "mojo/services/flog/interfaces/flog.mojom.h" |
+ |
+namespace mojo { |
+namespace flog { |
+ |
+// |
+// FORMATTED LOGGING |
+// |
+// The Flog class and associated macros provide a means of logging 'formatted' |
+// log messages serialized by Mojo. Flog uses an instance of FlogLogger to |
+// log events to the FlogService. Messages pulled from the FlogService can be |
+// deserialized using Mojo on behalf of log visualization and analysis tools. |
+// |
+// Message logging is performed using a 'channel', which is bound to a Mojo |
+// proxy for a particular interface. Mojo interfaces used for this purpose must |
+// be request-only, meaning the constituent methods must not have responses. |
+// |
+// Assume that we've defined the following interface: |
+// |
+// [ServiceName="my_namespace::MyFlogChannelInterface"] |
+// interface MyFlogChannelInterface { |
+// Thing1(int64 a, int32 b); |
+// Thing2(string c); |
+// }; |
+// |
+// Note that the ServiceName annotation is required. |
+// |
+// A channel instance may be defined, typically as a member of a class, as |
+// follows: |
+// |
+// FLOG_CHANNEL(MyFlogChannelInterface, my_flog_channel_instance_); |
+// |
+// If NDEBUG is defined, this compiles to nothing. Otherwise, it declares and |
+// initializes my_flog_channel_instance, which can be used via the FLOG macro: |
+// |
+// FLOG(my_flog_channel_instance_, Thing1(1234, 5678)); |
+// FLOG(my_flog_channel_instance_, Thing2("To the lifeboats!")); |
+// |
+// These invocations compile to nothing if NDEBUG is defined. Otherwise, they |
+// log messages to the channel represented by my_flog_channel_instance. |
+// |
+// FLOG_CHANNEL_DECL produces only a declaration for cases in which a channel |
+// must be declared but not defined (e.g. as a static class member). |
+// |
+// Logging to a channel does nothing unless the Flog class has been initialized |
+// with a call to Flog::Initialize. Flog::Initialize provides a FlogLogger |
+// implementation to be used for logging. Typically, this implementation would |
+// be acquired from the FlogService using CreateLogger. |
+// |
+ |
+#if defined(NDEBUG) |
+ |
+#define FLOG_INITIALIZE(app_or_logger, label) ((void)0) |
+#define FLOG_DESTROY() ((void)0) |
+#define FLOG_CHANNEL(channel_type, channel_name) |
+#define FLOG_CHANNEL_DECL(channel_type, channel_name) |
+#define FLOG(channel_name, call) ((void)0) |
+#define FLOG_ID(channel_name) 0 |
+ |
+#else |
+ |
+#define FLOG_INITIALIZE(app_or_logger, label) \ |
+ mojo::flog::Flog::Initialize(app_or_logger, label) |
+ |
+#define FLOG_DESTROY() mojo::flog::Flog::Destroy() |
+ |
+#define FLOG_CHANNEL(channel_type, channel_name) \ |
+ std::unique_ptr<mojo::flog::FlogProxy<channel_type>> channel_name = \ |
+ mojo::flog::FlogProxy<channel_type>::Create() |
+ |
+#define FLOG_CHANNEL_DECL(channel_type, channel_name) \ |
+ std::unique_ptr<mojo::flog::FlogProxy<channel_type>> channel_name |
+ |
+#define FLOG(channel_name, call) channel_name->call |
+ |
+#define FLOG_ID(channel_name) channel_name->channel()->id() |
+ |
+#endif |
+ |
+// Thread-safe logger for all channels in a given process. |
+class Flog { |
+ public: |
+ static void Initialize(ApplicationImpl* app, const std::string& label) { |
+ MOJO_DCHECK(!logger_); |
+ FlogServicePtr flog_service; |
+ FlogLoggerPtr flog_logger; |
+ ConnectToService(app->shell(), "mojo:flog", GetProxy(&flog_service)); |
+ flog_service->CreateLogger(GetProxy(&flog_logger), label); |
+ logger_ = flog_logger.Pass(); |
+ } |
+ |
+ // Sets the flog logger singleton. |
+ static void Initialize(FlogLoggerPtr flog_logger) { |
+ MOJO_DCHECK(!logger_); |
+ logger_ = flog_logger.Pass(); |
+ } |
+ |
+ // Deletes the flog logger singleton. |
+ static void Destroy() { |
+ MOJO_DCHECK(logger_); |
+ logger_.reset(); |
+ } |
+ |
+ // Allocates a unique id for a new channel. Never returns 0. |
+ static uint32_t AllocateChannelId() { return ++last_allocated_channel_id_; } |
+ |
+ // Logs the creation of a channel. |
+ static void LogChannelCreation(uint32_t channel_id, |
+ const char* channel_type_name) { |
+ if (!logger_) { |
+ return; |
+ } |
+ |
+ logger_->LogChannelCreation(GetTimeTicksNow(), channel_id, |
+ channel_type_name); |
+ } |
+ |
+ // Logs a channel message. |
+ static void LogChannelMessage(uint32_t channel_id, Message* message) { |
+ if (!logger_) { |
+ return; |
+ } |
+ |
+ Array<uint8_t> array = Array<uint8_t>::New(message->data_num_bytes()); |
+ memcpy(array.data(), message->data(), message->data_num_bytes()); |
+ logger_->LogChannelMessage(GetTimeTicksNow(), channel_id, array.Pass()); |
+ } |
+ |
+ // Logs the deletion of a channel. |
+ static void LogChannelDeletion(uint32_t channel_id) { |
+ if (!logger_) { |
+ return; |
+ } |
+ |
+ logger_->LogChannelDeletion(GetTimeTicksNow(), channel_id); |
+ } |
+ |
+ private: |
+ static std::atomic_ulong last_allocated_channel_id_; |
+ static FlogLoggerPtr logger_; |
+}; |
+ |
+// Channel backing a FlogProxy. |
+class FlogChannel : public MessageReceiverWithResponder { |
+ public: |
+ FlogChannel(const char* channel_type_name); |
+ |
+ ~FlogChannel() override; |
+ |
+ // Returns the channel id. |
+ uint32_t id() const { return id_; } |
+ |
+ // MessageReceiverWithResponder implementation. |
+ bool Accept(Message* message) override; |
+ |
+ bool AcceptWithResponder(Message* message, |
+ MessageReceiver* responder) override; |
+ |
+ private: |
+ uint32_t id_ = 0; |
+}; |
+ |
+template <typename T> |
+class FlogProxy : public T::Proxy_ { |
+ public: |
+ static std::unique_ptr<FlogProxy<T>> Create() { |
+ return std::unique_ptr<FlogProxy<T>>(new FlogProxy<T>()); |
+ } |
+ |
+ FlogChannel* channel() { |
+ return reinterpret_cast<FlogChannel*>(this->receiver_); |
+ } |
+ |
+ private: |
+ explicit FlogProxy() : T::Proxy_(new FlogChannel(T::Name_)) {} |
+}; |
+ |
+} // namespace flog |
+} // namespace mojo |
+ |
+#endif // MOJO_SERVICES_FLOG_CPP_FLOG_H_ |