blob: 22e258abc2dca688498ea138ab612a4975f196e5 [file] [log] [blame]
// 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/feedback_agent/attachments.h"
#include <fuchsia/mem/cpp/fidl.h>
#include <inttypes.h>
#include <lib/fit/promise.h>
#include <lib/fsl/vmo/file.h>
#include <lib/fsl/vmo/sized_vmo.h>
#include <lib/fsl/vmo/strings.h>
#include <lib/syslog/cpp/logger.h>
#include <lib/zx/debuglog.h>
#include <zircon/errors.h>
#include <zircon/status.h>
#include <zircon/syscalls/log.h>
#include <zircon/time.h>
#include <string>
#include <vector>
#include "src/developer/feedback_agent/inspect.h"
#include "src/developer/feedback_agent/log_listener.h"
#include "src/lib/fxl/strings/string_printf.h"
namespace fuchsia {
namespace feedback {
namespace {
// Timeout for a single asynchronous attachment, e.g., syslog collection.
const zx::duration kAttachmentTimeout = zx::sec(10);
// This is actually synchronous, but we return a fit::promise to match other
// attachment providers that are asynchronous.
fit::promise<fuchsia::mem::Buffer> GetKernelLog() {
zx::debuglog log;
const zx_status_t create_status =
zx::debuglog::create(zx::resource(), ZX_LOG_FLAG_READABLE, &log);
if (create_status != ZX_OK) {
FX_LOGS(ERROR) << "zx::debuglog::create failed: " << create_status << " ("
<< zx_status_get_string(create_status) << ")";
return fit::make_result_promise<fuchsia::mem::Buffer>(fit::error());
}
std::string kernel_log;
zx_log_record_t record;
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);
}
fsl::SizedVmo vmo;
if (!fsl::VmoFromString(kernel_log, &vmo)) {
FX_LOGS(ERROR) << "Failed to convert kernel log string to vmo";
return fit::make_result_promise<fuchsia::mem::Buffer>(fit::error());
}
return fit::make_ok_promise(std::move(vmo).ToTransport());
}
// This is actually synchronous, but we return a fit::promise to match other
// attachment providers that are asynchronous.
fit::promise<fuchsia::mem::Buffer> VmoFromFilename(
const std::string& filename) {
fsl::SizedVmo vmo;
if (!fsl::VmoFromFilename(filename, &vmo)) {
FX_LOGS(ERROR) << "Failed to read VMO from file " << filename;
return fit::make_result_promise<fuchsia::mem::Buffer>(fit::error());
}
return fit::make_ok_promise(std::move(vmo).ToTransport());
}
fit::promise<fuchsia::mem::Buffer> BuildValue(
const std::string& key, std::shared_ptr<::sys::ServiceDirectory> services) {
if (key == "build.snapshot") {
return VmoFromFilename("/config/build-info/snapshot");
} else if (key == "log.kernel") {
return GetKernelLog();
} else if (key == "log.system") {
return CollectSystemLog(services, kAttachmentTimeout);
} else if (key == "inspect") {
return CollectInspectData(kAttachmentTimeout);
} else {
FX_LOGS(WARNING) << "Unknown attachment " << key;
return fit::make_result_promise<fuchsia::mem::Buffer>(fit::error());
}
}
fit::promise<Attachment> BuildAttachment(
const std::string& key, std::shared_ptr<::sys::ServiceDirectory> services) {
return BuildValue(key, services)
.and_then([key](fuchsia::mem::Buffer& vmo) -> fit::result<Attachment> {
Attachment attachment;
attachment.key = key;
attachment.value = std::move(vmo);
return fit::ok(std::move(attachment));
})
.or_else([key]() {
FX_LOGS(WARNING) << "Failed to build attachment " << key;
return fit::error();
});
}
} // namespace
std::vector<fit::promise<Attachment>> GetAttachments(
std::shared_ptr<::sys::ServiceDirectory> services,
const std::set<std::string>& whitelist) {
if (whitelist.empty()) {
FX_LOGS(WARNING) << "Attachment whitelist is empty, nothing to retrieve";
return {};
}
std::vector<fit::promise<Attachment>> attachments;
for (const auto& key : whitelist) {
attachments.push_back(BuildAttachment(key, services));
}
return attachments;
}
} // namespace feedback
} // namespace fuchsia