blob: b811db4e62c301a5989e916672a159dc1338f7d9 [file] [log] [blame]
// Copyright (c) 2012 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.
#include "net/base/net_log.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/string_number_conversions.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "net/base/net_errors.h"
namespace net {
namespace {
// Returns parameters for logging data transferred events. Includes number of
// bytes transferred and, if the log level indicates bytes should be logged and
// |byte_count| > 0, the bytes themselves. The bytes are hex-encoded, since
// base::StringValue only supports UTF-8.
Value* BytesTransferredCallback(int byte_count,
const char* bytes,
NetLog::LogLevel log_level) {
DictionaryValue* dict = new DictionaryValue();
dict->SetInteger("byte_count", byte_count);
if (NetLog::IsLoggingBytes(log_level) && byte_count > 0)
dict->SetString("hex_encoded_bytes", base::HexEncode(bytes, byte_count));
return dict;
}
Value* SourceEventParametersCallback(const NetLog::Source source,
NetLog::LogLevel /* log_level */) {
if (!source.IsValid())
return NULL;
DictionaryValue* event_params = new DictionaryValue();
source.AddToEventParameters(event_params);
return event_params;
}
Value* NetLogIntegerCallback(const char* name,
int value,
NetLog::LogLevel /* log_level */) {
DictionaryValue* event_params = new DictionaryValue();
event_params->SetInteger(name, value);
return event_params;
}
Value* NetLogInt64Callback(const char* name,
int64 value,
NetLog::LogLevel /* log_level */) {
DictionaryValue* event_params = new DictionaryValue();
event_params->SetString(name, base::Int64ToString(value));
return event_params;
}
Value* NetLogStringCallback(const char* name,
const std::string* value,
NetLog::LogLevel /* log_level */) {
DictionaryValue* event_params = new DictionaryValue();
event_params->SetString(name, *value);
return event_params;
}
Value* NetLogString16Callback(const char* name,
const string16* value,
NetLog::LogLevel /* log_level */) {
DictionaryValue* event_params = new DictionaryValue();
event_params->SetString(name, *value);
return event_params;
}
} // namespace
const uint32 NetLog::Source::kInvalidId = 0;
NetLog::Source::Source() : type(SOURCE_NONE), id(kInvalidId) {
}
NetLog::Source::Source(SourceType type, uint32 id) : type(type), id(id) {
}
bool NetLog::Source::IsValid() const {
return id != kInvalidId;
}
void NetLog::Source::AddToEventParameters(DictionaryValue* event_params) const {
DictionaryValue* dict = new DictionaryValue();
dict->SetInteger("type", static_cast<int>(type));
dict->SetInteger("id", static_cast<int>(id));
event_params->Set("source_dependency", dict);
}
NetLog::ParametersCallback NetLog::Source::ToEventParametersCallback() const {
return base::Bind(&SourceEventParametersCallback, *this);
}
// static
bool NetLog::Source::FromEventParameters(Value* event_params, Source* source) {
DictionaryValue* dict;
DictionaryValue* source_dict;
int source_id;
int source_type;
if (!event_params ||
!event_params->GetAsDictionary(&dict) ||
!dict->GetDictionary("source_dependency", &source_dict) ||
!source_dict->GetInteger("id", &source_id) ||
!source_dict->GetInteger("type", &source_type)) {
*source = Source();
return false;
}
DCHECK_LE(0, source_id);
DCHECK_LT(source_type, NetLog::SOURCE_COUNT);
*source = Source(static_cast<SourceType>(source_type), source_id);
return true;
}
Value* NetLog::Entry::ToValue() const {
DictionaryValue* entry_dict(new DictionaryValue());
entry_dict->SetString("time", TickCountToString(time_));
// Set the entry source.
DictionaryValue* source_dict = new DictionaryValue();
source_dict->SetInteger("id", source_.id);
source_dict->SetInteger("type", static_cast<int>(source_.type));
entry_dict->Set("source", source_dict);
// Set the event info.
entry_dict->SetInteger("type", static_cast<int>(type_));
entry_dict->SetInteger("phase", static_cast<int>(phase_));
// Set the event-specific parameters.
if (parameters_callback_) {
Value* value = parameters_callback_->Run(log_level_);
if (value)
entry_dict->Set("params", value);
}
return entry_dict;
}
Value* NetLog::Entry::ParametersToValue() const {
if (parameters_callback_)
return parameters_callback_->Run(log_level_);
return NULL;
}
NetLog::Entry::Entry(
EventType type,
Source source,
EventPhase phase,
base::TimeTicks time,
const ParametersCallback* parameters_callback,
LogLevel log_level)
: type_(type),
source_(source),
phase_(phase),
time_(time),
parameters_callback_(parameters_callback),
log_level_(log_level) {
};
NetLog::Entry::~Entry() {
}
NetLog::ThreadSafeObserver::ThreadSafeObserver() : log_level_(LOG_BASIC),
net_log_(NULL) {
}
NetLog::ThreadSafeObserver::~ThreadSafeObserver() {
// Make sure we aren't watching a NetLog on destruction. Because the NetLog
// may pass events to each observer on multiple threads, we cannot safely
// stop watching a NetLog automatically from a parent class.
DCHECK(!net_log_);
}
NetLog::LogLevel NetLog::ThreadSafeObserver::log_level() const {
DCHECK(net_log_);
return log_level_;
}
NetLog* NetLog::ThreadSafeObserver::net_log() const {
return net_log_;
}
void NetLog::AddGlobalEntry(EventType type) {
AddEntry(type,
Source(net::NetLog::SOURCE_NONE, NextID()),
net::NetLog::PHASE_NONE,
NULL);
}
void NetLog::AddGlobalEntry(
EventType type,
const NetLog::ParametersCallback& parameters_callback) {
AddEntry(type,
Source(net::NetLog::SOURCE_NONE, NextID()),
net::NetLog::PHASE_NONE,
&parameters_callback);
}
// static
std::string NetLog::TickCountToString(const base::TimeTicks& time) {
int64 delta_time = (time - base::TimeTicks()).InMilliseconds();
return base::Int64ToString(delta_time);
}
// static
const char* NetLog::EventTypeToString(EventType event) {
switch (event) {
#define EVENT_TYPE(label) case TYPE_ ## label: return #label;
#include "net/base/net_log_event_type_list.h"
#undef EVENT_TYPE
default:
NOTREACHED();
return NULL;
}
}
// static
base::Value* NetLog::GetEventTypesAsValue() {
DictionaryValue* dict = new DictionaryValue();
for (int i = 0; i < EVENT_COUNT; ++i) {
dict->SetInteger(EventTypeToString(static_cast<EventType>(i)), i);
}
return dict;
}
// static
const char* NetLog::SourceTypeToString(SourceType source) {
switch (source) {
#define SOURCE_TYPE(label) case SOURCE_ ## label: return #label;
#include "net/base/net_log_source_type_list.h"
#undef SOURCE_TYPE
default:
NOTREACHED();
return NULL;
}
}
// static
base::Value* NetLog::GetSourceTypesAsValue() {
DictionaryValue* dict = new DictionaryValue();
for (int i = 0; i < SOURCE_COUNT; ++i) {
dict->SetInteger(SourceTypeToString(static_cast<SourceType>(i)), i);
}
return dict;
}
// static
const char* NetLog::EventPhaseToString(EventPhase phase) {
switch (phase) {
case PHASE_BEGIN:
return "PHASE_BEGIN";
case PHASE_END:
return "PHASE_END";
case PHASE_NONE:
return "PHASE_NONE";
}
NOTREACHED();
return NULL;
}
// static
bool NetLog::IsLoggingBytes(LogLevel log_level) {
return log_level == NetLog::LOG_ALL;
}
// static
bool NetLog::IsLoggingAllEvents(LogLevel log_level) {
return log_level <= NetLog::LOG_ALL_BUT_BYTES;
}
// static
NetLog::ParametersCallback NetLog::IntegerCallback(const char* name,
int value) {
return base::Bind(&NetLogIntegerCallback, name, value);
}
// static
NetLog::ParametersCallback NetLog::Int64Callback(const char* name,
int64 value) {
return base::Bind(&NetLogInt64Callback, name, value);
}
// static
NetLog::ParametersCallback NetLog::StringCallback(const char* name,
const std::string* value) {
DCHECK(value);
return base::Bind(&NetLogStringCallback, name, value);
}
// static
NetLog::ParametersCallback NetLog::StringCallback(const char* name,
const string16* value) {
DCHECK(value);
return base::Bind(&NetLogString16Callback, name, value);
}
void NetLog::OnAddObserver(ThreadSafeObserver* observer, LogLevel log_level) {
DCHECK(!observer->net_log_);
observer->net_log_ = this;
observer->log_level_ = log_level;
}
void NetLog::OnSetObserverLogLevel(ThreadSafeObserver* observer,
LogLevel log_level) {
DCHECK_EQ(this, observer->net_log_);
observer->log_level_ = log_level;
}
void NetLog::OnRemoveObserver(ThreadSafeObserver* observer) {
DCHECK_EQ(this, observer->net_log_);
observer->net_log_ = NULL;
}
void NetLog::AddEntry(EventType type,
const Source& source,
EventPhase phase,
const NetLog::ParametersCallback* parameters_callback) {
Entry entry(type, source, phase, base::TimeTicks::Now(),
parameters_callback, GetLogLevel());
OnAddEntry(entry);
}
void BoundNetLog::AddEntry(NetLog::EventType type,
NetLog::EventPhase phase) const {
if (!net_log_)
return;
net_log_->AddEntry(type, source_, phase, NULL);
}
void BoundNetLog::AddEntry(
NetLog::EventType type,
NetLog::EventPhase phase,
const NetLog::ParametersCallback& get_parameters) const {
if (!net_log_)
return;
net_log_->AddEntry(type, source_, phase, &get_parameters);
}
void BoundNetLog::AddEvent(NetLog::EventType type) const {
AddEntry(type, NetLog::PHASE_NONE);
}
void BoundNetLog::AddEvent(
NetLog::EventType type,
const NetLog::ParametersCallback& get_parameters) const {
AddEntry(type, NetLog::PHASE_NONE, get_parameters);
}
void BoundNetLog::BeginEvent(NetLog::EventType type) const {
AddEntry(type, NetLog::PHASE_BEGIN);
}
void BoundNetLog::BeginEvent(
NetLog::EventType type,
const NetLog::ParametersCallback& get_parameters) const {
AddEntry(type, NetLog::PHASE_BEGIN, get_parameters);
}
void BoundNetLog::EndEvent(NetLog::EventType type) const {
AddEntry(type, NetLog::PHASE_END);
}
void BoundNetLog::EndEvent(
NetLog::EventType type,
const NetLog::ParametersCallback& get_parameters) const {
AddEntry(type, NetLog::PHASE_END, get_parameters);
}
void BoundNetLog::AddEventWithNetErrorCode(NetLog::EventType event_type,
int net_error) const {
DCHECK_NE(ERR_IO_PENDING, net_error);
if (net_error >= 0) {
AddEvent(event_type);
} else {
AddEvent(event_type, NetLog::IntegerCallback("net_error", net_error));
}
}
void BoundNetLog::EndEventWithNetErrorCode(NetLog::EventType event_type,
int net_error) const {
DCHECK_NE(ERR_IO_PENDING, net_error);
if (net_error >= 0) {
EndEvent(event_type);
} else {
EndEvent(event_type, NetLog::IntegerCallback("net_error", net_error));
}
}
void BoundNetLog::AddByteTransferEvent(NetLog::EventType event_type,
int byte_count,
const char* bytes) const {
AddEvent(event_type, base::Bind(BytesTransferredCallback, byte_count, bytes));
}
NetLog::LogLevel BoundNetLog::GetLogLevel() const {
if (net_log_)
return net_log_->GetLogLevel();
return NetLog::LOG_BASIC;
}
bool BoundNetLog::IsLoggingBytes() const {
return NetLog::IsLoggingBytes(GetLogLevel());
}
bool BoundNetLog::IsLoggingAllEvents() const {
return NetLog::IsLoggingAllEvents(GetLogLevel());
}
// static
BoundNetLog BoundNetLog::Make(NetLog* net_log,
NetLog::SourceType source_type) {
if (!net_log)
return BoundNetLog();
NetLog::Source source(source_type, net_log->NextID());
return BoundNetLog(source, net_log);
}
} // namespace net