| 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_ | 
|  |