224 lines
5.6 KiB
C++
224 lines
5.6 KiB
C++
// Copyright 2013 The Flutter 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 <algorithm>
|
|
#include <cstring>
|
|
#include <iostream>
|
|
|
|
#include "flutter/fml/build_config.h"
|
|
#include "flutter/fml/log_level.h"
|
|
#include "flutter/fml/log_settings.h"
|
|
#include "flutter/fml/logging.h"
|
|
|
|
#if defined(FML_OS_ANDROID)
|
|
#include <android/log.h>
|
|
#elif defined(FML_OS_IOS)
|
|
#include <syslog.h>
|
|
#elif defined(OS_FUCHSIA)
|
|
#include <lib/syslog/structured_backend/cpp/fuchsia_syslog.h>
|
|
#include <lib/syslog/structured_backend/fuchsia_syslog.h>
|
|
#include <zircon/process.h>
|
|
#include "flutter/fml/platform/fuchsia/log_state.h"
|
|
#endif
|
|
|
|
namespace fml {
|
|
|
|
namespace {
|
|
|
|
#if !defined(OS_FUCHSIA)
|
|
const char* const kLogSeverityNames[kLogNumSeverities] = {
|
|
"INFO", "WARNING", "ERROR", "IMPORTANT", "FATAL"};
|
|
|
|
const char* GetNameForLogSeverity(LogSeverity severity) {
|
|
if (severity >= kLogInfo && severity < kLogNumSeverities) {
|
|
return kLogSeverityNames[severity];
|
|
}
|
|
return "UNKNOWN";
|
|
}
|
|
#endif
|
|
|
|
const char* StripDots(const char* path) {
|
|
while (strncmp(path, "../", 3) == 0) {
|
|
path += 3;
|
|
}
|
|
return path;
|
|
}
|
|
|
|
#if defined(OS_FUCHSIA)
|
|
|
|
zx_koid_t GetKoid(zx_handle_t handle) {
|
|
zx_info_handle_basic_t info;
|
|
zx_status_t status = zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info,
|
|
sizeof(info), nullptr, nullptr);
|
|
return status == ZX_OK ? info.koid : ZX_KOID_INVALID;
|
|
}
|
|
|
|
thread_local zx_koid_t tls_thread_koid{ZX_KOID_INVALID};
|
|
|
|
zx_koid_t GetCurrentThreadKoid() {
|
|
if (unlikely(tls_thread_koid == ZX_KOID_INVALID)) {
|
|
tls_thread_koid = GetKoid(zx_thread_self());
|
|
}
|
|
ZX_DEBUG_ASSERT(tls_thread_koid != ZX_KOID_INVALID);
|
|
return tls_thread_koid;
|
|
}
|
|
|
|
static zx_koid_t pid = GetKoid(zx_process_self());
|
|
|
|
static thread_local zx_koid_t tid = GetCurrentThreadKoid();
|
|
|
|
std::string GetProcessName(zx_handle_t handle) {
|
|
char process_name[ZX_MAX_NAME_LEN];
|
|
zx_status_t status = zx_object_get_property(
|
|
handle, ZX_PROP_NAME, &process_name, sizeof(process_name));
|
|
if (status != ZX_OK) {
|
|
process_name[0] = '\0';
|
|
}
|
|
return process_name;
|
|
}
|
|
|
|
static std::string process_name = GetProcessName(zx_process_self());
|
|
|
|
static const zx::socket& socket = LogState::Default().socket();
|
|
|
|
#endif
|
|
|
|
} // namespace
|
|
|
|
LogMessage::LogMessage(LogSeverity severity,
|
|
const char* file,
|
|
int line,
|
|
const char* condition)
|
|
: severity_(severity), file_(StripDots(file)), line_(line) {
|
|
#if !defined(OS_FUCHSIA)
|
|
stream_ << "[";
|
|
if (severity >= kLogInfo) {
|
|
stream_ << GetNameForLogSeverity(severity);
|
|
} else {
|
|
stream_ << "VERBOSE" << -severity;
|
|
}
|
|
stream_ << ":" << file_ << "(" << line_ << ")] ";
|
|
#endif
|
|
|
|
if (condition) {
|
|
stream_ << "Check failed: " << condition << ". ";
|
|
}
|
|
}
|
|
|
|
// static
|
|
thread_local std::ostringstream* LogMessage::capture_next_log_stream_ = nullptr;
|
|
|
|
namespace testing {
|
|
|
|
LogCapture::LogCapture() {
|
|
fml::LogMessage::CaptureNextLog(&stream_);
|
|
}
|
|
|
|
LogCapture::~LogCapture() {
|
|
fml::LogMessage::CaptureNextLog(nullptr);
|
|
}
|
|
|
|
std::string LogCapture::str() const {
|
|
return stream_.str();
|
|
}
|
|
|
|
} // namespace testing
|
|
|
|
// static
|
|
void LogMessage::CaptureNextLog(std::ostringstream* stream) {
|
|
LogMessage::capture_next_log_stream_ = stream;
|
|
}
|
|
|
|
LogMessage::~LogMessage() {
|
|
#if !defined(OS_FUCHSIA)
|
|
stream_ << std::endl;
|
|
#endif
|
|
if (capture_next_log_stream_) {
|
|
*capture_next_log_stream_ << stream_.str();
|
|
capture_next_log_stream_ = nullptr;
|
|
} else {
|
|
#if defined(FML_OS_ANDROID)
|
|
android_LogPriority priority =
|
|
(severity_ < 0) ? ANDROID_LOG_VERBOSE : ANDROID_LOG_UNKNOWN;
|
|
switch (severity_) {
|
|
case kLogImportant:
|
|
case kLogInfo:
|
|
priority = ANDROID_LOG_INFO;
|
|
break;
|
|
case kLogWarning:
|
|
priority = ANDROID_LOG_WARN;
|
|
break;
|
|
case kLogError:
|
|
priority = ANDROID_LOG_ERROR;
|
|
break;
|
|
case kLogFatal:
|
|
priority = ANDROID_LOG_FATAL;
|
|
break;
|
|
}
|
|
__android_log_write(priority, "flutter", stream_.str().c_str());
|
|
#elif defined(FML_OS_IOS)
|
|
syslog(LOG_ALERT, "%s", stream_.str().c_str());
|
|
#elif defined(OS_FUCHSIA)
|
|
FuchsiaLogSeverity severity;
|
|
switch (severity_) {
|
|
case kLogImportant:
|
|
case kLogInfo:
|
|
severity = FUCHSIA_LOG_INFO;
|
|
break;
|
|
case kLogWarning:
|
|
severity = FUCHSIA_LOG_WARNING;
|
|
break;
|
|
case kLogError:
|
|
severity = FUCHSIA_LOG_ERROR;
|
|
break;
|
|
case kLogFatal:
|
|
severity = FUCHSIA_LOG_FATAL;
|
|
break;
|
|
default:
|
|
if (severity_ < 0) {
|
|
severity = FUCHSIA_LOG_DEBUG;
|
|
} else {
|
|
// Unknown severity. Use INFO.
|
|
severity = FUCHSIA_LOG_INFO;
|
|
}
|
|
break;
|
|
}
|
|
fuchsia_syslog::LogBuffer buffer;
|
|
buffer.BeginRecord(severity, std::string_view(file_), line_,
|
|
std::string_view(stream_.str()), socket.borrow(), 0, pid,
|
|
tid);
|
|
if (!process_name.empty()) {
|
|
buffer.WriteKeyValue("tag", process_name);
|
|
}
|
|
if (auto tags_ptr = LogState::Default().tags()) {
|
|
for (auto& tag : *tags_ptr) {
|
|
buffer.WriteKeyValue("tag", tag);
|
|
}
|
|
}
|
|
buffer.FlushRecord();
|
|
#else
|
|
// Don't use std::cerr here, because it may not be initialized properly yet.
|
|
fprintf(stderr, "%s", stream_.str().c_str());
|
|
fflush(stderr);
|
|
#endif
|
|
}
|
|
|
|
if (severity_ >= kLogFatal) {
|
|
KillProcess();
|
|
}
|
|
}
|
|
|
|
int GetVlogVerbosity() {
|
|
return std::max(-1, kLogInfo - GetMinLogLevel());
|
|
}
|
|
|
|
bool ShouldCreateLogMessage(LogSeverity severity) {
|
|
return severity >= GetMinLogLevel();
|
|
}
|
|
|
|
void KillProcess() {
|
|
abort();
|
|
}
|
|
|
|
} // namespace fml
|