/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2020 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#include "namespace/ns_quarkdb/inspector/OutputSink.hh"
#include "namespace/utils/Checksum.hh"
#include
#include
#define SSTR(message) static_cast(std::ostringstream().flush() << message).str()
EOSNSNAMESPACE_BEGIN
//------------------------------------------------------------------------------
//! Convert to octal string
//------------------------------------------------------------------------------
static std::string to_octal_string(uint32_t v)
{
std::ostringstream ss;
ss << std::oct << v;
return ss.str();
}
//------------------------------------------------------------------------------
//! Return full path, if possible, otherwise empty
//------------------------------------------------------------------------------
static std::string populateFullPath(const eos::ns::FileMdProto& proto,
FileScanner::Item& item)
{
item.fullPath.wait();
if (item.fullPath.hasException()) {
return std::string();
}
std::string fullPath = std::move(item.fullPath).get();
if (fullPath.empty()) {
return std::string();
}
return SSTR(fullPath << proto.name());
}
//------------------------------------------------------------------------------
//! Return full path, if possible, otherwise empty
//------------------------------------------------------------------------------
static std::string populateFullPath(const eos::ns::ContainerMdProto& proto,
ContainerScanner::Item& item)
{
item.fullPath.wait();
if (item.fullPath.hasException()) {
return std::string();
}
std::string fullPath = std::move(item.fullPath).get();
if (fullPath.empty()) {
return std::string();
}
return fullPath;
}
//------------------------------------------------------------------------------
// Serialize locations vector
//------------------------------------------------------------------------------
template
static std::string serializeLocations(const T& vec)
{
std::ostringstream stream;
for (int i = 0; i < vec.size(); i++) {
stream << vec[i];
if (i != vec.size() - 1) {
stream << ",";
}
}
return stream.str();
}
//------------------------------------------------------------------------------
//! Populate map with container attributes
//------------------------------------------------------------------------------
static void populateMetadata(const eos::ns::ContainerMdProto& proto,
const ContainerPrintingOptions& opts, std::map& out)
{
if (opts.showId) {
out["cid"] = std::to_string(proto.id());
}
if (opts.showParent) {
out["parent_id"] = std::to_string(proto.parent_id());
}
if (opts.showUid) {
out["uid"] = std::to_string(proto.uid());
}
if (opts.showGid) {
out["gid"] = std::to_string(proto.gid());
}
if (opts.showTreeSize) {
out["tree_size"] = std::to_string(proto.tree_size());
}
if (opts.showMode) {
out["mode"] = to_octal_string(proto.mode());
}
if (opts.showMode) {
out["flags"] = to_octal_string(proto.flags());
}
if (opts.showName) {
out["name"] = proto.name();
}
if (opts.showCTime) {
out["ctime"] = Printing::timespecToTimestamp(Printing::parseTimespec(
proto.ctime()));
}
if (opts.showMTime) {
out["mtime"] = Printing::timespecToTimestamp(Printing::parseTimespec(
proto.mtime()));
}
if (opts.showSTime) {
out["stime"] = Printing::timespecToTimestamp(Printing::parseTimespec(
proto.stime()));
}
if (opts.showXAttr) {
for (auto it = proto.xattrs().begin(); it != proto.xattrs().end(); it++) {
out[SSTR("xattr." << it->first)] = it->second;
}
}
}
//------------------------------------------------------------------------------
//! Print everything known about a ContainerMD
//------------------------------------------------------------------------------
void OutputSink::print(const eos::ns::ContainerMdProto& proto,
const ContainerPrintingOptions& opts)
{
std::map out;
populateMetadata(proto, opts, out);
print(out);
}
//----------------------------------------------------------------------------
//! Print everything known about a ContainerMD -- custom path
//----------------------------------------------------------------------------
void OutputSink::printWithCustomPath(const eos::ns::ContainerMdProto& proto,
const ContainerPrintingOptions& opts,
const std::string& customPath)
{
std::map out;
out["path"] = customPath;
populateMetadata(proto, opts, out);
print(out);
}
//------------------------------------------------------------------------------
// Get count as string
//------------------------------------------------------------------------------
static std::string countAsString(folly::Future& fut)
{
fut.wait();
if (fut.hasException()) {
return "N/A";
}
uint64_t val = std::move(fut).get();
fut = val;
return std::to_string(val);
}
//------------------------------------------------------------------------------
//! Print everything known about a ContainerMD, including full path if available
//------------------------------------------------------------------------------
void OutputSink::print(const eos::ns::ContainerMdProto& proto,
const ContainerPrintingOptions& opts, ContainerScanner::Item& item,
bool showCounts)
{
std::map out;
populateMetadata(proto, opts, out);
std::string fullPath = populateFullPath(proto, item);
if (!fullPath.empty()) {
out["path"] = fullPath;
}
if (showCounts) {
out["file-count"] = countAsString(item.fileCount);
out["container-count"] = countAsString(item.containerCount);
}
print(out);
}
//------------------------------------------------------------------------------
//! Populate map with file attributes
//------------------------------------------------------------------------------
static void populateMetadata(const eos::ns::FileMdProto& proto,
const FilePrintingOptions& opts, std::map& out)
{
if (opts.showId) {
out["fid"] = std::to_string(proto.id());
}
if (opts.showContId) {
out["pid"] = std::to_string(proto.cont_id());
}
if (opts.showUid) {
out["uid"] = std::to_string(proto.uid());
}
if (opts.showGid) {
out["gid"] = std::to_string(proto.gid());
}
if (opts.showSize) {
out["size"] = std::to_string(proto.size());
}
if (opts.showLayoutId) {
out["layout_id"] = std::to_string(proto.layout_id());
}
if (opts.showFlags) {
out["flags"] = to_octal_string(proto.flags());
}
if (opts.showName) {
out["name"] = proto.name();
}
if (opts.showLinkName) {
out["link_name"] = proto.link_name();
}
if (opts.showCTime) {
out["ctime"] = Printing::timespecToTimestamp(Printing::parseTimespec(
proto.ctime()));
}
if (opts.showMTime) {
out["mtime"] = Printing::timespecToTimestamp(Printing::parseTimespec(
proto.mtime()));
}
if (opts.showChecksum) {
std::string xs;
eos::appendChecksumOnStringProtobuf(proto, xs);
out["xs"] = xs;
}
if (opts.showLocations) {
out["locations"] = serializeLocations(proto.locations());
}
if (opts.showLocations) {
out["unlink_locations"] = serializeLocations(proto.unlink_locations());
}
if (opts.showXAttr) {
for (auto it = proto.xattrs().begin(); it != proto.xattrs().end(); it++) {
out[SSTR("xattr." << it->first)] = it->second;
}
}
if (opts.showSTime) {
out["stime"] = Printing::timespecToTimestamp(Printing::parseTimespec(
proto.stime()));
}
if(opts.showATime) {
out["atime"] = Printing::timespecToTimestamp(Printing::parseTimespec(
proto.atime()));
}
}
//------------------------------------------------------------------------------
//! Print everything known about a FileMD
//------------------------------------------------------------------------------
void OutputSink::print(const eos::ns::FileMdProto& proto,
const FilePrintingOptions& opts)
{
std::map out;
populateMetadata(proto, opts, out);
print(out);
}
//----------------------------------------------------------------------------
// Print everything known about a FileMD -- custom path
//----------------------------------------------------------------------------
void OutputSink::printWithCustomPath(const eos::ns::FileMdProto& proto,
const FilePrintingOptions& opts,
const std::string& customPath)
{
std::map out;
out["path"] = customPath;
populateMetadata(proto, opts, out);
print(out);
}
//----------------------------------------------------------------------------
//! Print everything known about a FileMD -- Additional fields to add
//----------------------------------------------------------------------------
void OutputSink::printWithAdditionalFields(const eos::ns::FileMdProto& proto,
const FilePrintingOptions& opts,
std::map& extension)
{
populateMetadata(proto, opts, extension);
print(extension);
}
//------------------------------------------------------------------------------
//! Print everything known about a FileMD, including full path if available
//------------------------------------------------------------------------------
void OutputSink::print(const eos::ns::FileMdProto& proto,
const FilePrintingOptions& opts, FileScanner::Item& item)
{
std::map out;
populateMetadata(proto, opts, out);
std::string fullPath = populateFullPath(proto, item);
if (!fullPath.empty()) {
out["path"] = fullPath;
}
print(out);
}
//------------------------------------------------------------------------------
// Class StreamSink
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
StreamSink::StreamSink(std::ostream& out, std::ostream& err)
: OutputSink(out, err)
{}
//------------------------------------------------------------------------------
// Print implementation for map
//------------------------------------------------------------------------------
void StreamSink::print(const std::map& line)
{
for (auto it = line.begin(); it != line.end(); it++) {
if (it != line.begin()) {
mOut << " ";
}
mOut << Printing::escapeNonPrintable(it->first) << "=" <<
Printing::escapeNonPrintable(it->second);
}
mOut << std::endl;
}
//------------------------------------------------------------------------------
// Class JsonStreamSink
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
JsonStreamSink::JsonStreamSink(std::ostream& out, std::ostream& err)
: OutputSink(out, err), mFirst(true)
{
mOut << "[" << std::endl;
}
//------------------------------------------------------------------------------
// Destructor
//------------------------------------------------------------------------------
JsonStreamSink::~JsonStreamSink()
{
mOut << "]" << std::endl;
}
//------------------------------------------------------------------------------
// Print implementation
//------------------------------------------------------------------------------
void JsonStreamSink::print(const std::map& line)
{
if (!mFirst) {
mOut << "," << std::endl;
}
mFirst = false;
Json::Value json;
for (auto it = line.begin(); it != line.end(); it++) {
json[it->first] = it->second;
}
mOut << json;
}
//------------------------------------------------------------------------------
// Class JsonLinedStreamSink
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
JsonLinedStreamSink::JsonLinedStreamSink(std::ostream& out, std::ostream& err)
: OutputSink(out, err)
{
mBuilder["indentation"] = ""; // or whatever you like
mWriter.reset(mBuilder.newStreamWriter());
}
//------------------------------------------------------------------------------
// Print implementation
//------------------------------------------------------------------------------
void JsonLinedStreamSink::print(const std::map& line)
{
Json::Value json;
for (auto it = line.begin(); it != line.end(); it++) {
json[it->first] = it->second;
}
print(json);
}
//------------------------------------------------------------------------------
// Print JsonValue implementation
//------------------------------------------------------------------------------
void JsonLinedStreamSink::print(const Json::Value& jsonObj)
{
mWriter->write(jsonObj, &mOut);
mOut << std::endl;
}
EOSNSNAMESPACE_END