| // Copyright 2019 The Fuchsia 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 "src/developer/forensics/feedback_data/attachments/kernel_log_ptr.h" | |
| #include <inttypes.h> | |
| #include <lib/syslog/cpp/macros.h> | |
| #include <zircon/syscalls/log.h> | |
| #include "src/developer/forensics/utils/errors.h" | |
| #include "src/developer/forensics/utils/fit/promise.h" | |
| #include "src/lib/fxl/strings/string_printf.h" | |
| namespace forensics { | |
| namespace feedback_data { | |
| ::fit::promise<AttachmentValue> CollectKernelLog(async_dispatcher_t* dispatcher, | |
| std::shared_ptr<sys::ServiceDirectory> services, | |
| fit::Timeout timeout) { | |
| std::unique_ptr<BootLog> boot_log = std::make_unique<BootLog>(dispatcher, services); | |
| // We must store the promise in a variable due to the fact that the order of evaluation of | |
| // function parameters is undefined. | |
| auto logs = boot_log->GetLog(std::move(timeout)); | |
| return fit::ExtendArgsLifetimeBeyondPromise(/*promise=*/std::move(logs), | |
| /*args=*/std::move(boot_log)); | |
| } | |
| BootLog::BootLog(async_dispatcher_t* dispatcher, std::shared_ptr<sys::ServiceDirectory> services) | |
| : log_ptr_(dispatcher, services) {} | |
| ::fit::promise<AttachmentValue> BootLog::GetLog(fit::Timeout timeout) { | |
| log_ptr_->Get([this](zx::debuglog log) { | |
| if (log_ptr_.IsAlreadyDone()) { | |
| return; | |
| } | |
| // zx_log_record_t has a flexible array member, so we need to allocate the buffer explicitly. | |
| char buf[ZX_LOG_RECORD_MAX + 1]; | |
| zx_log_record_t* record = reinterpret_cast<zx_log_record_t*>(buf); | |
| std::string kernel_log; | |
| while (log.read(/*options=*/0, /*buffer=*/record, | |
| /*buffer_size=*/ZX_LOG_RECORD_MAX) > 0) { | |
| if (record->datalen && (record->data[record->datalen - 1] == '\n')) { | |
| record->datalen--; | |
| } | |
| record->data[record->datalen] = 0; | |
| kernel_log += fxl::StringPrintf("[%05d.%03d] %05" PRIu64 ".%05" PRIu64 "> %s\n", | |
| static_cast<int>(record->timestamp / 1000000000ULL), | |
| static_cast<int>((record->timestamp / 1000000ULL) % 1000ULL), | |
| record->pid, record->tid, record->data); | |
| } | |
| if (kernel_log.empty()) { | |
| FX_LOGS(ERROR) << "Empty kernel log"; | |
| log_ptr_.CompleteError(Error::kMissingValue); | |
| return; | |
| } | |
| log_ptr_.CompleteOk(kernel_log); | |
| }); | |
| return log_ptr_.WaitForDone(std::move(timeout)) | |
| .then([](const ::fit::result<std::string, Error>& result) { | |
| AttachmentValue value = | |
| (result.is_ok()) ? AttachmentValue(result.value()) : AttachmentValue(result.error()); | |
| return ::fit::ok(std::move(value)); | |
| }); | |
| } | |
| } // namespace feedback_data | |
| } // namespace forensics |