log-utils.cc 6.52 KB
Newer Older
1
// Copyright 2009 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/log-utils.h"
6 7 8 9

#include "src/assert-scope.h"
#include "src/base/platform/platform.h"
#include "src/objects-inl.h"
10
#include "src/string-stream.h"
11
#include "src/utils.h"
12
#include "src/version.h"
13 14 15 16

namespace v8 {
namespace internal {

17

18
const char* const Log::kLogToTemporaryFile = "&";
19
const char* const Log::kLogToConsole = "-";
20

21 22 23 24 25 26 27 28 29 30 31 32 33
// static
FILE* Log::CreateOutputHandle(const char* file_name) {
  // If we're logging anything, we need to open the log file.
  if (!Log::InitLogAtStart()) {
    return nullptr;
  } else if (strcmp(file_name, kLogToConsole) == 0) {
    return stdout;
  } else if (strcmp(file_name, kLogToTemporaryFile) == 0) {
    return base::OS::OpenTemporaryFile();
  } else {
    return base::OS::FOpen(file_name, base::OS::LogFileOpenMode);
  }
}
34

35 36 37 38 39 40
Log::Log(Logger* logger, const char* file_name)
    : is_stopped_(false),
      output_handle_(Log::CreateOutputHandle(file_name)),
      os_(output_handle_ == nullptr ? stdout : output_handle_),
      format_buffer_(NewArray<char>(kMessageBufferSize)),
      logger_(logger) {
41 42 43 44 45 46 47
  // --log-all enables all the log flags.
  if (FLAG_log_all) {
    FLAG_log_api = true;
    FLAG_log_code = true;
    FLAG_log_gc = true;
    FLAG_log_suspect = true;
    FLAG_log_handles = true;
48
    FLAG_log_internal_timer_events = true;
49 50 51 52 53
  }

  // --prof implies --log-code.
  if (FLAG_prof) FLAG_log_code = true;

54 55 56 57 58 59 60 61
  if (output_handle_ == nullptr) return;
  Log::MessageBuilder msg(this);
  LogSeparator kNext = LogSeparator::kSeparator;
  msg << "v8-version" << kNext << Version::GetMajor() << kNext
      << Version::GetMinor() << kNext << Version::GetBuild() << kNext
      << Version::GetPatch();
  if (strlen(Version::GetEmbedder()) != 0) {
    msg << kNext << Version::GetEmbedder();
62
  }
63 64
  msg << kNext << Version::IsCandidate();
  msg.WriteToLogFile();
65 66
}

67
FILE* Log::Close() {
68 69
  FILE* result = nullptr;
  if (output_handle_ != nullptr) {
70 71 72 73 74
    if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) {
      fclose(output_handle_);
    } else {
      result = output_handle_;
    }
75
  }
76
  output_handle_ = nullptr;
77

78 79
  DeleteArray(format_buffer_);
  format_buffer_ = nullptr;
80

81
  is_stopped_ = false;
82
  return result;
83 84
}

85
Log::MessageBuilder::MessageBuilder(Log* log)
86 87
    : log_(log), lock_guard_(&log_->mutex_) {
  DCHECK_NOT_NULL(log_->format_buffer_);
88 89 90
}


91
void Log::MessageBuilder::Append(const char* format, ...) {
92 93
  va_list args;
  va_start(args, format);
94
  AppendVA(format, args);
95 96 97 98
  va_end(args);
}


99
void Log::MessageBuilder::AppendVA(const char* format, va_list args) {
100 101 102
  Vector<char> buf(log_->format_buffer_, Log::kMessageBufferSize);
  int length = v8::internal::VSNPrintF(buf, format, args);
  // {length} is -1 if output was truncated.
103
  if (length == -1) length = Log::kMessageBufferSize;
104 105
  DCHECK_LE(length, Log::kMessageBufferSize);
  AppendStringPart(log_->format_buffer_, length);
106 107
}

108
void Log::MessageBuilder::Append(String* string) {
109
  DisallowHeapAllocation no_gc;  // Ensure string stay valid.
110 111
  std::unique_ptr<char[]> characters =
      string->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
112
  AppendString(characters.get());
113 114
}

115
void Log::MessageBuilder::AppendAddress(Address addr) {
116
  Append("0x%" V8PRIxPTR, reinterpret_cast<intptr_t>(addr));
117
}
118

119
void Log::MessageBuilder::AppendSymbolName(Symbol* symbol) {
120
  DCHECK(symbol);
121 122
  OFStream& os = log_->os_;
  os << "symbol(";
123
  if (!symbol->name()->IsUndefined(symbol->GetIsolate())) {
124
    os << "\"";
125
    AppendDetailed(String::cast(symbol->name()), false);
126
    os << "\" ";
127
  }
128
  os << "hash " << std::hex << symbol->Hash() << std::dec << ")";
129 130 131
}

void Log::MessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
132
  if (str == nullptr) return;
133
  DisallowHeapAllocation no_gc;  // Ensure string stay valid.
134
  OFStream& os = log_->os_;
135 136
  int limit = str->length();
  if (limit > 0x1000) limit = 0x1000;
137
  if (show_impl_info) {
138 139 140 141
    os << (str->IsOneByteRepresentation() ? 'a' : '2');
    if (StringShape(str).IsExternal()) os << 'e';
    if (StringShape(str).IsInternalized()) os << '#';
    os << ':' << str->length() << ':';
142
  }
143
  AppendStringPart(str, limit);
144 145
}

146
void Log::MessageBuilder::AppendString(String* str) {
147
  if (str == nullptr) return;
148
  int len = str->length();
149 150 151 152 153 154 155
  AppendStringPart(str, len);
}

void Log::MessageBuilder::AppendString(const char* string) {
  for (const char* p = string; *p != '\0'; p++) {
    this->AppendCharacter(*p);
  }
156 157
}

158
void Log::MessageBuilder::AppendStringPart(String* str, int len) {
159 160 161
  DCHECK_LE(len, str->length());
  DisallowHeapAllocation no_gc;  // Ensure string stay valid.
  // TODO(cbruni): unify escaping.
162 163
  for (int i = 0; i < len; i++) {
    uc32 c = str->Get(i);
164 165
    if (c <= 0xff) {
      AppendCharacter(static_cast<char>(c));
166
    } else {
167 168
      // Escape any non-ascii range characters.
      Append("\\u%04x", c);
169 170 171 172
    }
  }
}

173
void Log::MessageBuilder::AppendStringPart(const char* str, int len) {
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
  for (int i = 0; i < len; i++) {
    DCHECK_NE(str[i], '\0');
    this->AppendCharacter(str[i]);
  }
}

void Log::MessageBuilder::AppendCharacter(char c) {
  OFStream& os = log_->os_;
  // A log entry (separate by commas) cannot contain commas or line-brakes.
  if (c >= 32 && c <= 126) {
    if (c == ',') {
      // Escape commas directly.
      os << "\x2c";
    } else {
      // Directly append any printable ascii character.
      os << c;
    }
  } else {
    // Escape any non-printable haracters.
    Append("\\x%02x", c);
  }
195 196
}

197
void Log::MessageBuilder::WriteToLogFile() { log_->os_ << std::endl; }
198

199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
template <>
Log::MessageBuilder& Log::MessageBuilder::operator<<<const char*>(
    const char* string) {
  this->AppendString(string);
  return *this;
}

template <>
Log::MessageBuilder& Log::MessageBuilder::operator<<<char>(char c) {
  this->AppendCharacter(c);
  return *this;
}

template <>
Log::MessageBuilder& Log::MessageBuilder::operator<<<String*>(String* string) {
  this->AppendString(string);
  return *this;
}

template <>
Log::MessageBuilder& Log::MessageBuilder::operator<<<Symbol*>(Symbol* symbol) {
  this->AppendSymbolName(symbol);
  return *this;
}

template <>
Log::MessageBuilder& Log::MessageBuilder::operator<<<Name*>(Name* name) {
  if (name->IsString()) {
    this->AppendString(String::cast(name));
  } else {
    this->AppendSymbolName(Symbol::cast(name));
  }
  return *this;
}

template <>
Log::MessageBuilder& Log::MessageBuilder::operator<<<LogSeparator>(
    LogSeparator separator) {
  log_->os_ << ',';
  return *this;
}

241 242
}  // namespace internal
}  // namespace v8