blob: 2a2cd37fb116ad053da153a101d819d276a4c627 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __SLAVE_CONTAINER_LOGGER_LIB_LOGROTATE_HPP__
#define __SLAVE_CONTAINER_LOGGER_LIB_LOGROTATE_HPP__
#include <stdio.h>
#include <mesos/slave/container_logger.hpp>
#include <mesos/slave/containerizer.hpp>
#include <stout/bytes.hpp>
#include <stout/flags.hpp>
#include <stout/option.hpp>
#include <stout/os/constants.hpp>
#include <stout/os/exists.hpp>
#include <stout/os/pagesize.hpp>
#include <stout/os/shell.hpp>
#include "slave/container_loggers/logrotate.hpp"
namespace mesos {
namespace internal {
namespace logger {
// Forward declaration.
class LogrotateContainerLoggerProcess;
// These flags are loaded twice: once when the `ContainerLogger` module
// is created and each time before launching containers. The flags loaded
// at module creation act as global default values, whereas flags loaded
// prior to containers can override the global values.
struct LoggerFlags : public virtual flags::FlagsBase
{
LoggerFlags()
{
add(&LoggerFlags::max_stdout_size,
"max_stdout_size",
"Maximum size, in bytes, of a single stdout log file.\n"
"Defaults to 10 MB. Must be at least 1 (memory) page.",
Megabytes(10),
&LoggerFlags::validateSize);
add(&LoggerFlags::logrotate_stdout_options,
"logrotate_stdout_options",
"Additional config options to pass into 'logrotate' for stdout.\n"
"This string will be inserted into a 'logrotate' configuration file.\n"
"i.e.\n"
" /path/to/stdout {\n"
" <logrotate_stdout_options>\n"
" size <max_stdout_size>\n"
" }\n"
"NOTE: The 'size' option will be overridden by this module.");
add(&LoggerFlags::max_stderr_size,
"max_stderr_size",
"Maximum size, in bytes, of a single stderr log file.\n"
"Defaults to 10 MB. Must be at least 1 (memory) page.",
Megabytes(10),
&LoggerFlags::validateSize);
add(&LoggerFlags::logrotate_stderr_options,
"logrotate_stderr_options",
"Additional config options to pass into 'logrotate' for stderr.\n"
"This string will be inserted into a 'logrotate' configuration file.\n"
"i.e.\n"
" /path/to/stderr {\n"
" <logrotate_stderr_options>\n"
" size <max_stderr_size>\n"
" }\n"
"NOTE: The 'size' option will be overridden by this module.");
}
static Option<Error> validateSize(const Bytes& value)
{
if (value.bytes() < os::pagesize()) {
return Error(
"Expected --max_stdout_size and --max_stderr_size of "
"at least " + stringify(os::pagesize()) + " bytes");
}
return None();
}
Bytes max_stdout_size;
Option<std::string> logrotate_stdout_options;
Bytes max_stderr_size;
Option<std::string> logrotate_stderr_options;
};
struct Flags : public virtual LoggerFlags
{
Flags()
{
add(&Flags::environment_variable_prefix,
"environment_variable_prefix",
"Prefix for environment variables meant to modify the behavior of\n"
"the logrotate logger for the specific container being launched.\n"
"The logger will look for four prefixed environment variables in the\n"
"container's 'CommandInfo's 'Environment':\n"
" * MAX_STDOUT_SIZE\n"
" * LOGROTATE_STDOUT_OPTIONS\n"
" * MAX_STDERR_SIZE\n"
" * LOGROTATE_STDERR_OPTIONS\n"
"If present, these variables will overwrite the global values set\n"
"via module parameters.",
"CONTAINER_LOGGER_");
add(&Flags::launcher_dir,
"launcher_dir",
"Directory path of Mesos binaries. The logrotate container logger\n"
"will find the '" + mesos::internal::logger::rotate::NAME + "'\n"
"binary file under this directory.",
PKGLIBEXECDIR,
[](const std::string& value) -> Option<Error> {
std::string executablePath =
path::join(value, mesos::internal::logger::rotate::NAME);
if (!os::exists(executablePath)) {
return Error("Cannot find: " + executablePath);
}
return None();
});
add(&Flags::logrotate_path,
"logrotate_path",
"If specified, the logrotate container logger will use the specified\n"
"'logrotate' instead of the system's 'logrotate'.",
"logrotate",
[](const std::string& value) -> Option<Error> {
// Check if `logrotate` exists via the help command.
// TODO(josephw): Consider a more comprehensive check.
Try<std::string> helpCommand =
os::shell(value + " --help > " + os::DEV_NULL);
if (helpCommand.isError()) {
return Error(
"Failed to check logrotate: " + helpCommand.error());
}
return None();
});
add(&Flags::libprocess_num_worker_threads,
"libprocess_num_worker_threads",
"Number of Libprocess worker threads.\n"
"Defaults to 8. Must be at least 1.",
8u,
[](const size_t& value) -> Option<Error> {
if (value < 1u) {
return Error(
"Expected --libprocess_num_worker_threads of at least 1");
}
return None();
});
}
std::string environment_variable_prefix;
std::string launcher_dir;
std::string logrotate_path;
size_t libprocess_num_worker_threads;
};
// The `LogrotateContainerLogger` is a container logger that utilizes the
// `logrotate` utility to strictly constrain total size of a container's
// stdout and stderr log files. All `logrotate` configuration options
// (besides `size`, which this module uses) are supported. See `Flags` above.
class LogrotateContainerLogger : public mesos::slave::ContainerLogger
{
public:
LogrotateContainerLogger(const Flags& _flags);
~LogrotateContainerLogger() override;
// This is a noop. The logrotate container logger has nothing to initialize.
Try<Nothing> initialize() override;
process::Future<mesos::slave::ContainerIO> prepare(
const ContainerID& containerId,
const mesos::slave::ContainerConfig& containerConfig) override;
protected:
Flags flags;
process::Owned<LogrotateContainerLoggerProcess> process;
};
} // namespace logger {
} // namespace internal {
} // namespace mesos {
#endif // __SLAVE_CONTAINER_LOGGER_LIB_LOGROTATE_HPP__