// Copyright (c) 2011 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 NET_BASE_NET_LOG_H_
#define NET_BASE_NET_LOG_H_
#pragma once

#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "net/base/net_api.h"

class Value;

namespace base {
class TimeTicks;
}

namespace net {

// NetLog is the destination for log messages generated by the network stack.
// Each log message has a "source" field which identifies the specific entity
// that generated the message (for example, which URLRequest or which
// SocketStream).
//
// To avoid needing to pass in the "source id" to the logging functions, NetLog
// is usually accessed through a BoundNetLog, which will always pass in a
// specific source ID.
//
// ******** The NetLog (and associated logging) is a work in progress ********
//
// TODO(eroman): Remove the 'const' qualitifer from the BoundNetLog methods.
// TODO(eroman): Start a new Source each time URLRequest redirects
//               (simpler to reason about each as a separate entity).

class NET_API NetLog {
 public:
  enum EventType {
#define EVENT_TYPE(label) TYPE_ ## label,
#include "net/base/net_log_event_type_list.h"
#undef EVENT_TYPE
  };

  // The 'phase' of an event trace (whether it marks the beginning or end
  // of an event.).
  enum EventPhase {
    PHASE_NONE,
    PHASE_BEGIN,
    PHASE_END,
  };

  // The "source" identifies the entity that generated the log message.
  enum SourceType {
#define SOURCE_TYPE(label, value) SOURCE_ ## label = value,
#include "net/base/net_log_source_type_list.h"
#undef SOURCE_TYPE
  };

  // Identifies the entity that generated this log. The |id| field should
  // uniquely identify the source, and is used by log observers to infer
  // message groupings. Can use NetLog::NextID() to create unique IDs.
  struct NET_API Source {
    static const uint32 kInvalidId = 0;

    Source() : type(SOURCE_NONE), id(kInvalidId) {}
    Source(SourceType type, uint32 id) : type(type), id(id) {}
    bool is_valid() const { return id != kInvalidId; }

    // The caller takes ownership of the returned Value*.
    Value* ToValue() const;

    SourceType type;
    uint32 id;
  };

  // Base class for associating additional parameters with an event. Log
  // observers need to know what specific derivations of EventParameters a
  // particular EventType uses, in order to get at the individual components.
  class NET_API EventParameters
      : public base::RefCountedThreadSafe<EventParameters> {
   public:
    EventParameters() {}
    virtual ~EventParameters() {}

    // Serializes the parameters to a Value tree. This is intended to be a
    // lossless conversion, which is used to serialize the parameters to JSON.
    // The caller takes ownership of the returned Value*.
    virtual Value* ToValue() const = 0;

   private:
    DISALLOW_COPY_AND_ASSIGN(EventParameters);
  };

  // Specifies the granularity of events that should be emitted to the log.
  enum LogLevel {
    // Log everything possible, even if it is slow and memory expensive.
    // Includes logging of transferred bytes.
    LOG_ALL,

    // Log all events, but do not include the actual transferred bytes as
    // parameters for bytes sent/received events.
    LOG_ALL_BUT_BYTES,

    // Only log events which are cheap, and don't consume much memory.
    LOG_BASIC,
  };

  NetLog() {}
  virtual ~NetLog() {}

  // Emits an event to the log stream.
  //  |type| - The type of the event.
  //  |time| - The time when the event occurred.
  //  |source| - The source that generated the event.
  //  |phase| - An optional parameter indicating whether this is the start/end
  //            of an action.
  //  |params| - Optional (may be NULL) parameters for this event.
  //             The specific subclass of EventParameters is defined
  //             by the contract for events of this |type|.
  //             TODO(eroman): Take a scoped_refptr<> instead.
  virtual void AddEntry(EventType type,
                        const base::TimeTicks& time,
                        const Source& source,
                        EventPhase phase,
                        EventParameters* params) = 0;

  // Returns a unique ID which can be used as a source ID.
  virtual uint32 NextID() = 0;

  // Returns the logging level for this NetLog. This is used to avoid computing
  // and saving expensive log entries.
  virtual LogLevel GetLogLevel() const = 0;

  // Converts a time to the string format that the NetLog uses to represent
  // times.  Strings are used since integers may overflow.
  static std::string TickCountToString(const base::TimeTicks& time);

  // Returns a C-String symbolic name for |event_type|.
  static const char* EventTypeToString(EventType event_type);

  // Returns a list of all the available EventTypes.
  static std::vector<EventType> GetAllEventTypes();

  // Returns a C-String symbolic name for |source_type|.
  static const char* SourceTypeToString(SourceType source_type);

  // Returns a C-String symbolic name for |event_phase|.
  static const char* EventPhaseToString(EventPhase event_phase);

  // Serializes the specified event to a DictionaryValue.
  // If |use_strings| is true, uses strings rather than numeric ids.
  static Value* EntryToDictionaryValue(NetLog::EventType type,
                                       const base::TimeTicks& time,
                                       const NetLog::Source& source,
                                       NetLog::EventPhase phase,
                                       NetLog::EventParameters* params,
                                       bool use_strings);

 private:
  DISALLOW_COPY_AND_ASSIGN(NetLog);
};

// Helper that binds a Source to a NetLog, and exposes convenience methods to
// output log messages without needing to pass in the source.
class NET_API BoundNetLog {
 public:
  BoundNetLog() : net_log_(NULL) {}

  BoundNetLog(const NetLog::Source& source, NetLog* net_log)
      : source_(source), net_log_(net_log) {
  }

  // Convenience methods that call through to the NetLog, passing in the
  // currently bound source.
  void AddEntry(NetLog::EventType type,
                NetLog::EventPhase phase,
                const scoped_refptr<NetLog::EventParameters>& params) const;

  void AddEntryWithTime(
      NetLog::EventType type,
      const base::TimeTicks& time,
      NetLog::EventPhase phase,
      const scoped_refptr<NetLog::EventParameters>& params) const;

  // Convenience methods that call through to the NetLog, passing in the
  // currently bound source, current time, and a fixed "capture phase"
  // (begin, end, or none).
  void AddEvent(NetLog::EventType event_type,
                const scoped_refptr<NetLog::EventParameters>& params) const;
  void BeginEvent(NetLog::EventType event_type,
                  const scoped_refptr<NetLog::EventParameters>& params) const;
  void EndEvent(NetLog::EventType event_type,
                const scoped_refptr<NetLog::EventParameters>& params) const;

  // Just like EndEvent, except |net_error| is a net error code.  If it's
  // negative, a parameter called "net_error" with a value of |net_error| is
  // associated with the event.  Otherwise, the end event has no parameters.
  // |net_error| must not be ERR_IO_PENDING, as it's not a true error.
  void EndEventWithNetErrorCode(NetLog::EventType event_type,
                                int net_error) const;

  // Logs a byte transfer event to the NetLog.  Determines whether to log the
  // received bytes or not based on the current logging level.
  void AddByteTransferEvent(NetLog::EventType event_type,
                            int byte_count, char* bytes) const;

  NetLog::LogLevel GetLogLevel() const;

  // Returns true if the log level is LOG_ALL.
  bool IsLoggingBytes() const;

  // Returns true if the log level is LOG_ALL or LOG_ALL_BUT_BYTES.
  bool IsLoggingAllEvents() const;

  // Helper to create a BoundNetLog given a NetLog and a SourceType. Takes care
  // of creating a unique source ID, and handles the case of NULL net_log.
  static BoundNetLog Make(NetLog* net_log, NetLog::SourceType source_type);

  const NetLog::Source& source() const { return source_; }
  NetLog* net_log() const { return net_log_; }

 private:
  NetLog::Source source_;
  NetLog* net_log_;
};

// NetLogStringParameter is a subclass of EventParameters that encapsulates a
// single std::string parameter.
class NetLogStringParameter : public NetLog::EventParameters {
 public:
  // |name| must be a string literal.
  NetLogStringParameter(const char* name, const std::string& value);
  virtual ~NetLogStringParameter();

  const std::string& value() const {
    return value_;
  }

  virtual Value* ToValue() const;

 private:
  const char* const name_;
  const std::string value_;
};

// NetLogIntegerParameter is a subclass of EventParameters that encapsulates a
// single integer parameter.
class NetLogIntegerParameter : public NetLog::EventParameters {
 public:
  // |name| must be a string literal.
  NetLogIntegerParameter(const char* name, int value)
      : name_(name), value_(value) {}

  int value() const {
    return value_;
  }

  virtual Value* ToValue() const;

 private:
  const char* name_;
  const int value_;
};

// NetLogSourceParameter is a subclass of EventParameters that encapsulates a
// single NetLog::Source parameter.
class NET_API NetLogSourceParameter : public NetLog::EventParameters {
 public:
  // |name| must be a string literal.
  NetLogSourceParameter(const char* name, const NetLog::Source& value)
      : name_(name), value_(value) {}

  const NetLog::Source& value() const {
    return value_;
  }

  virtual Value* ToValue() const;

 private:
  const char* name_;
  const NetLog::Source value_;
};

// ScopedNetLogEvent logs a begin event on creation, and the corresponding end
// event on destruction.
class NET_TEST ScopedNetLogEvent {
 public:
  ScopedNetLogEvent(const BoundNetLog& net_log,
                    NetLog::EventType event_type,
                    const scoped_refptr<NetLog::EventParameters>& params);

  ~ScopedNetLogEvent();

  // Sets the parameters that will logged on object destruction.  Can be called
  // at most once for a given ScopedNetLogEvent object.  If not called, the end
  // event will have no parameters.
  void SetEndEventParameters(
      const scoped_refptr<NetLog::EventParameters>& end_event_params);

  const BoundNetLog& net_log() const;

 private:
  BoundNetLog net_log_;
  const NetLog::EventType event_type_;
  scoped_refptr<NetLog::EventParameters> end_event_params_;
};

}  // namespace net

#endif  // NET_BASE_NET_LOG_H_
