| /* |
| * Copyright 2015 Twitter, Inc. |
| * |
| * Licensed 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. |
| */ |
| |
| #include <signal.h> |
| #include <stdlib.h> |
| |
| #include <chrono> |
| #include <cstddef> |
| #include <map> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "glog/logging.h" |
| #include "config/heron-config.h" |
| |
| #include "basics/basics.h" |
| #include "basics/execmeta.h" |
| |
| namespace heron { |
| namespace common { |
| |
| static ExecutableMetadata gExecMeta; |
| |
| /** |
| * Set the execution metadata for the program. Several values are |
| * populated including |
| * |
| * - name and instance of the program, if any |
| * - whether it is a unit test |
| * - user who compiled, host of compilation and time of compilation |
| * - name of the package and its version |
| * |
| * \param argv0 |
| * Name of the program calling initialize |
| * |
| * \param instance |
| * Instance id of the program calling initialize |
| * |
| * \param testing |
| * To indicate whether the program is a unit test |
| * |
| */ |
| static void SetMetadata(const char* argv0, const char* instance, bool testing) { |
| // set the name of the program and its instance |
| gExecMeta.setName(argv0); |
| gExecMeta.setInstance(instance != nullptr ? instance : "0"); |
| |
| // set if it is a unit test |
| gExecMeta.setUnitTest(testing); |
| |
| // set the compile user, host and time |
| gExecMeta.setCompileUser(PACKAGE_COMPILE_USER); |
| gExecMeta.setCompileHost(PACKAGE_COMPILE_HOST); |
| gExecMeta.setCompileTime(PACKAGE_COMPILE_TIME); |
| |
| // set the start time of compilation |
| auto start = std::chrono::system_clock::now(); |
| gExecMeta.setStartTime(std::chrono::system_clock::to_time_t(start)); |
| |
| // set the package name and version |
| gExecMeta.setPackage(PACKAGE_NAME); |
| gExecMeta.setVersion(PACKAGE_VERSION); |
| |
| // set the major and minor version |
| std::string sversion(PACKAGE_VERSION); |
| std::string smajor(sversion, 0, sversion.find_first_of(".")); |
| |
| std::string sminor(sversion, sversion.find_first_of(".") + 1, |
| sversion.find_last_of(".") - sversion.find_first_of(".")); |
| |
| gExecMeta.setMajorVersion(smajor.c_str()); |
| gExecMeta.setMinorVersion(sminor.c_str()); |
| |
| // set the patch number |
| std::string patch(sversion, sversion.find_last_of(".") + 1); |
| gExecMeta.setPatchNumber(patch.c_str()); |
| } |
| |
| /** |
| * Function to initialize logging. It is used by other initialization |
| * functions. During initialization, it sets several values such as |
| * |
| * - test log directory, if the program is a test |
| * - log directory if it is actual Heron program |
| * - set the log file prefix and log directory |
| * - set the maximum size of the log file |
| * - install signal handler for processing SIGSEGV |
| * |
| */ |
| static void InitLogging() { |
| // set the log directory |
| gExecMeta.setLogDirectory(gExecMeta.unitTest() ? constTestLogsDirectory : constLogsDirectory); |
| |
| // get the basename of the file path |
| std::string bname = FileUtils::baseName(gExecMeta.name()); |
| |
| // form the log file prefix |
| std::string log_prefix(bname); |
| log_prefix.append("-").append(gExecMeta.instance()); |
| |
| // finally set the log file prefix |
| gExecMeta.setLogPrefix(log_prefix.c_str()); |
| |
| // configure glog parameters |
| FLAGS_stderrthreshold = 3; // FATAL |
| |
| // set the max log size to 100MB |
| FLAGS_max_log_size = 100; |
| |
| // set the default logging directory |
| FLAGS_log_dir = gExecMeta.logDirectory(); |
| |
| // set the default flush interval to 10 seconds |
| FLAGS_logbufsecs = 10; |
| |
| // enable logging only in the INFO file. This will contain |
| // all messages >=INFO Severity |
| for (google::LogSeverity s = google::WARNING; s < google::NUM_SEVERITIES; s++) |
| google::SetLogDestination(s, ""); |
| |
| // init the logging |
| google::InitGoogleLogging(gExecMeta.logPrefix().c_str()); |
| |
| // do an initial prune, in case, if there are some files to trim |
| PruneLogs(); |
| |
| // install the google signal handler for SIGSEGV |
| google::InstallFailureSignalHandler(); |
| } |
| |
| /** |
| * Helper function to initialize a Heron program. It is used by |
| * It initializes the execution metadata, logs, etc. It is the |
| * first function to be called in main() |
| * |
| * \param argv0 |
| * Name of the program calling initialize |
| * |
| * \param instance |
| * Instance id of the program calling initialize |
| */ |
| static void InitHelper(const char* argv0, const char* instance, bool istest) { |
| CHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR); |
| |
| // create execution meta data object |
| SetMetadata(argv0, instance, istest); |
| |
| // init the logging |
| InitLogging(); |
| |
| // init the random number system |
| ::srand(time(nullptr)); |
| } |
| |
| /** |
| * Function to initialize programs that have multiple instances. |
| * It initializes the execution metadata, logging framework, etc. |
| * It is the first function to be called in main() |
| * |
| * \param argv0 |
| * Name of the program calling initialize |
| * |
| * \param instance |
| * Instance id of the program calling initialize |
| */ |
| void Initialize(const char* argv0, const char* instance) { InitHelper(argv0, instance, false); } |
| |
| /** |
| * Function to initialize singleton programs. It initializes the |
| * execution metadata, logs, etc. It is the first function to be |
| * called in main() |
| * |
| * \param argv0 |
| * Name of the program calling initialize |
| */ |
| void Initialize(const char* argv0) { |
| std::string prog(argv0); |
| |
| // use a different initializer depending on if it a unit test program? |
| if (prog.rfind("_unittest") != std::string::npos) { |
| InitHelper(argv0, nullptr, true); |
| } else { |
| InitHelper(argv0, nullptr, false); |
| } |
| |
| LOG(INFO) << "Starting " << gExecMeta.name() << " " << gExecMeta.package() << " " |
| << "v" << gExecMeta.version() << " " << gExecMeta.compileUser() << "@" |
| << gExecMeta.compileHost() << " on " << gExecMeta.compileTime() << std::endl; |
| } |
| |
| void Shutdown() { google::ShutdownGoogleLogging(); } |
| |
| /** |
| * Utility function to prune the log files |
| */ |
| void PruneLogs() { |
| std::vector<std::string> files; |
| std::map<time_t, std::string> ordered_files; |
| |
| // get the log prefix and files in the log directory |
| const std::string& file_prefix = gExecMeta.logPrefix(); |
| FileUtils::listFiles(gExecMeta.logDirectory(), files); |
| |
| // find the files that contain the give prefix |
| for (size_t i = 0; i < files.size(); ++i) { |
| if (files[i].find(file_prefix) != std::string::npos) { |
| // form the full file path |
| std::string filePath(gExecMeta.logDirectory()); |
| filePath.append("/").append(files[i]); |
| |
| // ignore if it a sym link file |
| if (FileUtils::is_symlink(filePath)) continue; |
| |
| // get the last time of modification |
| time_t tmodified = FileUtils::getModifiedTime(filePath); |
| |
| // insert into the set of files to be examined |
| std::pair<time_t, std::string> logfile; |
| logfile = make_pair(tmodified, filePath); |
| ordered_files.insert(logfile); |
| } |
| } |
| |
| // remove the files that are old |
| while (ordered_files.size() > constMaxNumLogFiles) { |
| FileUtils::removeFile(ordered_files.begin()->second); |
| LOG(INFO) << "Pruned log file " << ordered_files.begin()->second; |
| ordered_files.erase(ordered_files.begin()); |
| } |
| } |
| |
| void FlushLogs() { google::FlushLogFiles(google::INFO); } |
| } // namespace common |
| } // namespace heron |