blob: 6b53ae8298c052b5ddf461b776e8a0050532d9ed [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 "log_listener.h"
#include <fuchsia/diagnostics/cpp/fidl.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/fit/bridge.h>
#include <lib/fit/promise.h>
#include <lib/fit/result.h>
#include <lib/sys/cpp/service_directory.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/status.h>
#include "dockyard_proxy.h"
#include "harvester.h"
#include "src/developer/system_monitor/lib/dockyard/dockyard.h"
#include "src/lib/fsl/vmo/strings.h"
namespace harvester {
LogListener::LogListener(const std::shared_ptr<sys::ServiceDirectory>& services)
: services_(services) {}
fit::promise<> LogListener::Listen(
std::function<void(std::vector<const std::string>)> content_callback) {
// Manages a completer/consumer for notifiying callers when listener closes.
fit::bridge<> bridge;
fuchsia::diagnostics::ArchiveAccessorPtr archive;
services_->Connect(archive.NewRequest());
// Configure Diagnostics stream for structured logs.
stream_parameters_.set_data_type(fuchsia::diagnostics::DataType::LOGS);
stream_parameters_.set_stream_mode(
fuchsia::diagnostics::StreamMode::SNAPSHOT_THEN_SUBSCRIBE);
stream_parameters_.set_format(fuchsia::diagnostics::Format::JSON);
archive->StreamDiagnostics(std::move(stream_parameters_),
iterator_.NewRequest());
GetLogData(content_callback, std::move(bridge.completer));
return bridge.consumer.promise_or(fit::error());
}
void LogListener::GetLogData(
std::function<void(std::vector<const std::string>)> content_callback,
fit::completer<>&& completer) {
iterator_->GetNext(
[this, content_callback = std::move(content_callback),
completer = std::move(completer)](auto result) mutable {
if (result.is_err()) {
FX_LOGS(WARNING) << "Failed to retrieve next log batch:"
<< std::to_string(static_cast<size_t>(result.err()));
completer.complete_error();
return;
}
std::vector<fuchsia::diagnostics::FormattedContent> batch =
std::move(result.response().batch);
// "An empty vector implies that the data hierarchy has been fully
// iterated".
// https://fuchsia.dev/reference/fidl/fuchsia.diagnostics#fuchsia.diagnostics/BatchIterator.GetNext
if (batch.empty()) {
FX_LOGS(INFO) << "Done getting logs.";
completer.complete_ok();
return;
}
std::vector<const std::string> logs;
for (const auto& chunk : batch) {
if (!chunk.is_json()) {
FX_LOGS(WARNING) << "Missing JSON log chunk, skipping";
continue;
}
std::string json;
if (!fsl::StringFromVmo(chunk.json(), &json)) {
FX_LOGS(WARNING)
<< "Failed to convert Log data chunk to string, skipping";
continue;
}
logs.emplace_back(json);
}
content_callback(logs);
GetLogData(std::move(content_callback), std::move(completer));
});
}
} // namespace harvester