sapling/eden/fs/telemetry/SubprocessScribeLogger.h
Chad Austin 9a5f0093f2 introduce a scribe logger that communicates with scribe_cat
Summary: Introduce a new ScribeLogger class that spawns and maintains a process. Log messages are newline-delimited and written to the process's stdin. If the process stops responding or responds too slowly, log messages are dropped.

Reviewed By: pkaush

Differential Revision: D17777215

fbshipit-source-id: c998d10c73fc103122d69ae19c5d84f58b7939d2
2019-10-22 12:42:54 -07:00

78 lines
2.0 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
#pragma once
#include <folly/Subprocess.h>
#include <folly/Synchronized.h>
#include <list>
#include "eden/fs/telemetry/ScribeLogger.h"
namespace facebook {
namespace eden {
/**
* SubprocessScribeLogger manages an external unix process and asynchronously
* forwards newline-delimited messages to its stdin.
*/
class SubprocessScribeLogger : public ScribeLogger {
public:
/**
* Launch `executable` with `category` as the first argument.
*/
SubprocessScribeLogger(const char* executable, folly::StringPiece category);
/**
* Launch the process specified at argv[0] with the given argv, and forward
* its stdout to `stdoutFd`, if non-negative. Otherwise, output goes to
* /dev/null.
*/
explicit SubprocessScribeLogger(
const std::vector<std::string>& argv,
int stdoutFd = -1);
/**
* Waits for the managed process to exit. If it is hung and doesn't complete,
* terminates the process. Either way, this destructor will completed within a
* bounded amount of time.
*/
~SubprocessScribeLogger();
/**
* Forwards a log message to the external process. Must not contain newlines,
* since that is how the process distinguishes between messages.
*
* If the writer process is not keeping up, messages are dropped.
*/
void log(std::string message) override;
using ScribeLogger::log;
private:
void closeProcess();
void writerThread();
struct State {
bool shouldStop = false;
bool didStop = false;
/// Sum of sizes of queued messages.
size_t totalBytes = 0;
/// Invariant: empty if didStop is true
std::list<std::string> messages;
};
folly::Subprocess process_;
std::thread writerThread_;
folly::Synchronized<State, std::mutex> state_;
std::condition_variable newMessageOrStop_;
std::condition_variable allMessagesWritten_;
};
} // namespace eden
} // namespace facebook