diff --git a/doc/usage.md b/doc/usage.md index c96d99155..ab31e4105 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -285,3 +285,10 @@ CodeCompass_webserver \ The server will be available in a browser on [`http://localhost:6251`](http://localhost:6251). + +### Logging + +In both the parser and the webserver it is possible to write the logs to a given directory. +This feature can be enabled by passing the `--logtarget` command line option with the full +path to the directory to be used for storing the log files. +If this argument is not specified, the logs will be written to the terminal only. \ No newline at end of file diff --git a/parser/src/parser.cpp b/parser/src/parser.cpp index 4c263d15b..63ffad303 100644 --- a/parser/src/parser.cpp +++ b/parser/src/parser.cpp @@ -70,6 +70,9 @@ po::options_description commandLineArguments() po::value()->default_value(trivial::info), "Logging legel of the parser. Possible values are: debug, info, warning, " "error, critical.") + ("logtarget", po::value(), + "This is the path to the folder where the logging output files will be written. " + "If omitted, the output will be on the console only.") ("jobs,j", po::value()->default_value(4), "Number of threads the parsers can use.") ("skip,s", po::value>(), @@ -219,7 +222,7 @@ int main(int argc, char* argv[]) cc::parser::PluginHandler pHandler(PARSER_PLUGIN_DIR); - cc::util::initLogger(); + cc::util::initConsoleLogger(); //--- Process command line arguments ---// @@ -229,6 +232,17 @@ int main(int argc, char* argv[]) po::store(po::command_line_parser(argc, argv) .options(desc).allow_unregistered().run(), vm); + if (vm.count("logtarget")) + { + vm.at("logtarget").value() = cc::util::getLoggingBase( vm["logtarget"].as() + , vm["name"].as() + ); + if (!cc::util::initFileLogger(vm["logtarget"].as() + "parser.log")) + { + vm.at("logtarget").value() = std::string(); + } + } + //--- Skip parser list ---// std::vector skipParserList; diff --git a/plugins/search/common/CMakeLists.txt b/plugins/search/common/CMakeLists.txt index 5c1b900c1..50bb6a261 100644 --- a/plugins/search/common/CMakeLists.txt +++ b/plugins/search/common/CMakeLists.txt @@ -9,6 +9,7 @@ add_jar(searchcommonjava ${CMAKE_CURRENT_SOURCE_DIR}/src/cc/search/analysis/Location.java ${CMAKE_CURRENT_SOURCE_DIR}/src/cc/search/analysis/SourceTextAnalyzer.java ${CMAKE_CURRENT_SOURCE_DIR}/src/cc/search/analysis/SourceTextTokenizer.java + ${CMAKE_CURRENT_SOURCE_DIR}/src/cc/search/common/FileLoggerInitializer.java ${CMAKE_CURRENT_SOURCE_DIR}/src/cc/search/common/IndexFields.java ${CMAKE_CURRENT_SOURCE_DIR}/src/cc/search/common/SuggestionDatabase.java ${CMAKE_CURRENT_SOURCE_DIR}/src/cc/search/common/NFSFriendlyLockFactory.java diff --git a/plugins/search/common/src/cc/search/common/FileLoggerInitializer.java b/plugins/search/common/src/cc/search/common/FileLoggerInitializer.java new file mode 100644 index 000000000..606313010 --- /dev/null +++ b/plugins/search/common/src/cc/search/common/FileLoggerInitializer.java @@ -0,0 +1,28 @@ +package cc.search.common; + +import cc.search.common.config.CommonOptions; + +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.logging.FileHandler; +import java.util.logging.SimpleFormatter; + +/** + * Adds file to logging when needed + */ +public class FileLoggerInitializer { + public static void addFileOutput(CommonOptions options_, Logger log_, String pluginName_) { + String filePathField = options_.logFilePath + pluginName_ + ".log"; + if (!options_.logFilePath.isEmpty()) { + try { + FileHandler fileHandler = new FileHandler(filePathField, false); + SimpleFormatter formatter = new SimpleFormatter(); + fileHandler.setFormatter(formatter); + log_.addHandler(fileHandler); + log_.info("Logging started to file: " + filePathField); + } catch (Exception ex) { + log_.log(Level.WARNING, "Could not add logs to file: " + filePathField, ex); + } + } + } +} diff --git a/plugins/search/common/src/cc/search/common/config/CommonOptions.java b/plugins/search/common/src/cc/search/common/config/CommonOptions.java index f94d63dfa..908ea06d4 100644 --- a/plugins/search/common/src/cc/search/common/config/CommonOptions.java +++ b/plugins/search/common/src/cc/search/common/config/CommonOptions.java @@ -16,6 +16,11 @@ public abstract class CommonOptions { * Index database path */ public String indexDirPath; + /** + * Logging file path + * (if there is no file logging, empty string) + */ + public String logFilePath = ""; /** * Input file descriptor for thrift IPC. */ @@ -77,6 +82,15 @@ protected void setFromCommandLineArguments(List args_) argIter.remove(); } break; + case "-logTarget": + if (!argIter.hasNext()) { + throw new InvalidValueException("No path for -logTarget"); + } else { + argIter.remove(); + logFilePath = argIter.next(); + argIter.remove(); + } + break; case "-ipcInFd": if (!argIter.hasNext()) { throw new InvalidValueException("-ipcInFd is empty"); @@ -136,6 +150,7 @@ public static String getUsage() { + "\t-ipcInFd fd\n\t\tFile descriptor for IPC IN.\n" + "\t-ipcOutFd id\n\t\tFile descriptor for IPC OUT.\n" + "\t-useSimpleFileLock\n\t\tUse NFS friendly file locks.\n" + + "\t-logTarget\n\t\tPath to logging file.\n" + "\t-cleanupLocks\n\t\tCleanup locks before first lock..\n"; } } \ No newline at end of file diff --git a/plugins/search/common/src/cc/search/common/config/LogConfigurator.java b/plugins/search/common/src/cc/search/common/config/LogConfigurator.java index 11ff27694..44b86c79c 100644 --- a/plugins/search/common/src/cc/search/common/config/LogConfigurator.java +++ b/plugins/search/common/src/cc/search/common/config/LogConfigurator.java @@ -25,7 +25,7 @@ public LogConfigurator() { logManager.readConfiguration(cfgStream); } catch (IOException | SecurityException ex) { - Logger.getLogger(LogConfigurator.class.getName()).log(Level.SEVERE, + Logger.getGlobal().log(Level.SEVERE, "Failed to configure custom log propeties!", ex); } } diff --git a/plugins/search/common/src/cc/search/common/ipc/IPCProcessor.java b/plugins/search/common/src/cc/search/common/ipc/IPCProcessor.java index 553eb6cd6..d4f37c8e0 100644 --- a/plugins/search/common/src/cc/search/common/ipc/IPCProcessor.java +++ b/plugins/search/common/src/cc/search/common/ipc/IPCProcessor.java @@ -22,8 +22,7 @@ public class IPCProcessor implements AutoCloseable { /** * Logger. */ - private static final Logger _log = Logger.getLogger( - IPCProcessor.class.getName()); + private static final Logger _log = Logger.getGlobal(); /** * Processor for thrift messages. */ diff --git a/plugins/search/indexer/include/indexer/indexerprocess.h b/plugins/search/indexer/include/indexer/indexerprocess.h index f33fca1cf..7de66a18a 100644 --- a/plugins/search/indexer/include/indexer/indexerprocess.h +++ b/plugins/search/indexer/include/indexer/indexerprocess.h @@ -64,7 +64,8 @@ class IndexerProcess : const std::string& indexDatabase_, const std::string& compassRoot_, OpenMode openMode_, - LockMode lockMode_ = LockMode::Simple); + LockMode lockMode_ = LockMode::Simple, + const std::string& logTarget_ = ""); /** * Closes the I/O pipe so the child process will exit if it finished. Also diff --git a/plugins/search/indexer/indexer-java/src/cc/search/analysis/SourceAnalyzer.java b/plugins/search/indexer/indexer-java/src/cc/search/analysis/SourceAnalyzer.java index c67edbffc..5d8c5ff1a 100644 --- a/plugins/search/indexer/indexer-java/src/cc/search/analysis/SourceAnalyzer.java +++ b/plugins/search/indexer/indexer-java/src/cc/search/analysis/SourceAnalyzer.java @@ -20,8 +20,7 @@ public final class SourceAnalyzer extends AnalyzerWrapper { /** * Logger. */ - private static final Logger _log = Logger.getLogger(SourceAnalyzer.class - .getName()); + private static final Logger _log = Logger.getGlobal(); /** * Analyzer for a full path. */ diff --git a/plugins/search/indexer/indexer-java/src/cc/search/analysis/tags/CTags.java b/plugins/search/indexer/indexer-java/src/cc/search/analysis/tags/CTags.java index 3a603000b..b9d56240c 100644 --- a/plugins/search/indexer/indexer-java/src/cc/search/analysis/tags/CTags.java +++ b/plugins/search/indexer/indexer-java/src/cc/search/analysis/tags/CTags.java @@ -19,8 +19,7 @@ class CTags implements TagGenerator { /** * Logger. */ - private final static Logger _log = Logger.getLogger(CTags.class - .getName()); + private final static Logger _log = Logger.getGlobal(); /** * Filter terminator string for ctags. */ diff --git a/plugins/search/indexer/indexer-java/src/cc/search/analysis/tags/SourceTagGenerator.java b/plugins/search/indexer/indexer-java/src/cc/search/analysis/tags/SourceTagGenerator.java index 044148da7..f178e53da 100644 --- a/plugins/search/indexer/indexer-java/src/cc/search/analysis/tags/SourceTagGenerator.java +++ b/plugins/search/indexer/indexer-java/src/cc/search/analysis/tags/SourceTagGenerator.java @@ -21,8 +21,7 @@ public class SourceTagGenerator implements TagGenerator { /** * Logger. */ - private static final Logger _log = Logger.getLogger(SourceTagGenerator.class - .getName()); + private static final Logger _log = Logger.getGlobal(); /** * Options array for initializing _artf460600CTags. */ diff --git a/plugins/search/indexer/indexer-java/src/cc/search/analysis/tags/TagGeneratorManager.java b/plugins/search/indexer/indexer-java/src/cc/search/analysis/tags/TagGeneratorManager.java index 4df24fa49..eeb7def1a 100644 --- a/plugins/search/indexer/indexer-java/src/cc/search/analysis/tags/TagGeneratorManager.java +++ b/plugins/search/indexer/indexer-java/src/cc/search/analysis/tags/TagGeneratorManager.java @@ -14,8 +14,7 @@ public final class TagGeneratorManager implements AutoCloseable { /** * Logger. */ - private final static Logger _log = Logger.getLogger( - TagGeneratorManager.class.getName()); + private final static Logger _log = Logger.getGlobal(); /** * Singleton instance. */ diff --git a/plugins/search/indexer/indexer-java/src/cc/search/indexer/AbstractIndexer.java b/plugins/search/indexer/indexer-java/src/cc/search/indexer/AbstractIndexer.java index 8501b7ed4..3ff1d8e6e 100644 --- a/plugins/search/indexer/indexer-java/src/cc/search/indexer/AbstractIndexer.java +++ b/plugins/search/indexer/indexer-java/src/cc/search/indexer/AbstractIndexer.java @@ -42,8 +42,7 @@ abstract public class AbstractIndexer { /** * Logger. */ - private static final Logger _log = Logger.getLogger(AbstractIndexer - .class.getName()); + private static final Logger _log = Logger.getGlobal(); /** * Field type for storing tags. */ diff --git a/plugins/search/indexer/indexer-java/src/cc/search/indexer/FileIndexer.java b/plugins/search/indexer/indexer-java/src/cc/search/indexer/FileIndexer.java index 0c0d36e89..58fa8cfe7 100644 --- a/plugins/search/indexer/indexer-java/src/cc/search/indexer/FileIndexer.java +++ b/plugins/search/indexer/indexer-java/src/cc/search/indexer/FileIndexer.java @@ -16,8 +16,7 @@ public class FileIndexer extends AbstractIndexer { /** * Logger. */ - private static final Logger _log = Logger.getLogger(FileIndexer.class - .getName()); + private static final Logger _log = Logger.getGlobal(); /** * File path to index. */ diff --git a/plugins/search/indexer/indexer-java/src/cc/search/indexer/app/Indexer.java b/plugins/search/indexer/indexer-java/src/cc/search/indexer/app/Indexer.java index 0f4d234ff..fb34ce0c5 100644 --- a/plugins/search/indexer/indexer-java/src/cc/search/indexer/app/Indexer.java +++ b/plugins/search/indexer/indexer-java/src/cc/search/indexer/app/Indexer.java @@ -4,6 +4,7 @@ import cc.parser.search.IndexerService; import cc.search.analysis.SourceAnalyzer; import cc.search.analysis.tags.TagGeneratorManager; +import cc.search.common.FileLoggerInitializer; import cc.search.common.ipc.IPCProcessor; import cc.search.common.config.InvalidValueException; import cc.search.common.config.UnknownArgumentException; @@ -40,7 +41,7 @@ public class Indexer implements AutoCloseable, IndexerService.Iface { /** * Logger. */ - private static final Logger _log = Logger.getLogger(Indexer.class.getName()); + private static final Logger _log = Logger.getGlobal(); /** * Command line options. */ @@ -82,6 +83,8 @@ public class Indexer implements AutoCloseable, IndexerService.Iface { private Indexer(Options options_) throws IOException { _options = options_; + FileLoggerInitializer.addFileOutput(_options, _log, "indexer"); + try { _indexDir = FSDirectory.open(new File(_options.indexDirPath), _options.createLockFactory()); diff --git a/plugins/search/indexer/indexer-java/src/cc/search/suggestion/DatabaseBuilder.java b/plugins/search/indexer/indexer-java/src/cc/search/suggestion/DatabaseBuilder.java index d1a44683b..583245943 100644 --- a/plugins/search/indexer/indexer-java/src/cc/search/suggestion/DatabaseBuilder.java +++ b/plugins/search/indexer/indexer-java/src/cc/search/suggestion/DatabaseBuilder.java @@ -27,8 +27,7 @@ public final class DatabaseBuilder { /** * Logger. */ - private static final Logger _log - = Logger.getLogger(DatabaseBuilder.class.getName()); + private static final Logger _log = Logger.getGlobal(); /** * An index reader for the main index database. */ diff --git a/plugins/search/indexer/src/indexerprocess.cpp b/plugins/search/indexer/src/indexerprocess.cpp index 1534eeac4..c2064f62d 100644 --- a/plugins/search/indexer/src/indexerprocess.cpp +++ b/plugins/search/indexer/src/indexerprocess.cpp @@ -30,7 +30,8 @@ IndexerProcess::IndexerProcess( const std::string& indexDatabase_, const std::string& compassRoot_, IndexerProcess::OpenMode openMode_, - IndexerProcess::LockMode lockMode_) + IndexerProcess::LockMode lockMode_, + const std::string& logTarget_) { openPipe(_pipeFd2[0], _pipeFd2[1]); @@ -60,12 +61,13 @@ IndexerProcess::IndexerProcess( "java", JAVAMEMORYAMOUNT, "-classpath", classpath.c_str(), "-Djava.util.logging.config.class=cc.search.common.config.LogConfigurator", - "-Djava.util.logging.SimpleFormatter.format=[%4$s] %5$s%6$s%n", + "-Djava.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tT [%4$s] %5$s%6$s%n", logLevelOpt.c_str(), "cc.search.indexer.app.Indexer", "-indexDB", indexDatabase_.c_str(), "-ipcInFd", inFd.c_str(), - "-ipcOutFd", outFd.c_str() + "-ipcOutFd", outFd.c_str(), + "-logTarget", logTarget_.c_str() }; switch (openMode_) diff --git a/plugins/search/parser/src/searchparser.cpp b/plugins/search/parser/src/searchparser.cpp index a0a79de4b..9306e04cd 100644 --- a/plugins/search/parser/src/searchparser.cpp +++ b/plugins/search/parser/src/searchparser.cpp @@ -70,7 +70,11 @@ SearchParser::SearchParser(ParserContext& ctx_) : AbstractParser(ctx_), _indexProcess.reset(new IndexerProcess( _searchDatabase, ctx_.compassRoot, - IndexerProcess::OpenMode::Create)); + IndexerProcess::OpenMode::Create, + IndexerProcess::LockMode::Simple, + ctx_.options.count("logtarget") + ? ctx_.options["logtarget"].as() + : "")); } catch (const IndexerProcess::Failure& ex_) { diff --git a/plugins/search/service/include/service/serviceprocess.h b/plugins/search/service/include/service/serviceprocess.h index c8e85c2c6..319788aba 100644 --- a/plugins/search/service/include/service/serviceprocess.h +++ b/plugins/search/service/include/service/serviceprocess.h @@ -33,7 +33,8 @@ class ServiceProcess : public SearchServiceIf, public util::PipedProcess * @param indexDatabase_ path to a index database */ ServiceProcess(const std::string& indexDatabase_, - const std::string& compassRoot_) : + const std::string& compassRoot_, + const std::string& logTarget_ = "") : _indexDatabase(indexDatabase_) { openPipe(_pipeFd2[0], _pipeFd2[1]); @@ -63,7 +64,7 @@ class ServiceProcess : public SearchServiceIf, public util::PipedProcess "-classpath", classpath.c_str(), //"-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8666", "-Djava.util.logging.config.class=cc.search.common.config.LogConfigurator", - "-Djava.util.logging.SimpleFormatter.format=[%4$s] %5$s%6$s%n", + "-Djava.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tT [%4$s] %5$s%6$s%n", logLevelOpt.c_str(), "cc.search.service.app.service.ServiceApp", "-indexDB", _indexDatabase.c_str(), @@ -71,6 +72,7 @@ class ServiceProcess : public SearchServiceIf, public util::PipedProcess "-ipcOutFd", outFd.c_str(), "-useSimpleFileLock", "-cleanupLocks", + "-logTarget", logTarget_.c_str(), nullptr); LOG(error) << "execlp failed!"; diff --git a/plugins/search/service/search-java/src/cc/search/analysis/QueryAnalyzer.java b/plugins/search/service/search-java/src/cc/search/analysis/QueryAnalyzer.java index 400f1af2c..480bfb139 100644 --- a/plugins/search/service/search-java/src/cc/search/analysis/QueryAnalyzer.java +++ b/plugins/search/service/search-java/src/cc/search/analysis/QueryAnalyzer.java @@ -17,8 +17,7 @@ public class QueryAnalyzer extends AnalyzerWrapper { /** * Logger. */ - private static final Logger _log = Logger.getLogger(QueryAnalyzer.class. - getName()); + private static final Logger _log = Logger.getGlobal(); /** * A simple analyzer for queries. */ diff --git a/plugins/search/service/search-java/src/cc/search/analysis/query/HIPDQuery.java b/plugins/search/service/search-java/src/cc/search/analysis/query/HIPDQuery.java index b4d8c2f58..d0ecce586 100644 --- a/plugins/search/service/search-java/src/cc/search/analysis/query/HIPDQuery.java +++ b/plugins/search/service/search-java/src/cc/search/analysis/query/HIPDQuery.java @@ -50,8 +50,7 @@ public class HIPDQuery extends Query { /** * Logger. */ - private static final Logger _log = Logger.getLogger(HIPDQuery.class. - getName()); + private static final Logger _log = Logger.getGlobal(); /** * The default value of the maximal allowed difference. */ diff --git a/plugins/search/service/search-java/src/cc/search/match/matcher/MasterMatcherFactory.java b/plugins/search/service/search-java/src/cc/search/match/matcher/MasterMatcherFactory.java index 951398d85..bf96f3127 100644 --- a/plugins/search/service/search-java/src/cc/search/match/matcher/MasterMatcherFactory.java +++ b/plugins/search/service/search-java/src/cc/search/match/matcher/MasterMatcherFactory.java @@ -15,8 +15,7 @@ public class MasterMatcherFactory implements ResultMatcherFactory { /** * Logger. */ - private static final Logger _log = Logger.getLogger(MasterMatcherFactory. - class.getName()); + private static final Logger _log = Logger.getGlobal(); /** * Matcher wrapper for matching with multiple matchers. */ diff --git a/plugins/search/service/search-java/src/cc/search/match/matcher/TagKindMatcherFactory.java b/plugins/search/service/search-java/src/cc/search/match/matcher/TagKindMatcherFactory.java index 9356e845b..0aab1f2a8 100644 --- a/plugins/search/service/search-java/src/cc/search/match/matcher/TagKindMatcherFactory.java +++ b/plugins/search/service/search-java/src/cc/search/match/matcher/TagKindMatcherFactory.java @@ -22,8 +22,7 @@ class TagKindMatcherFactory implements ResultMatcherFactory { /** * Logger. */ - private static final Logger _log = Logger.getLogger(TagKindMatcherFactory. - class.getName()); + private static final Logger _log = Logger.getGlobal(); /** * Token filter for filtering relevant tokens by its kind. */ diff --git a/plugins/search/service/search-java/src/cc/search/service/app/SearchAppCommon.java b/plugins/search/service/search-java/src/cc/search/service/app/SearchAppCommon.java index 696b1e2f2..39d49ef86 100644 --- a/plugins/search/service/search-java/src/cc/search/service/app/SearchAppCommon.java +++ b/plugins/search/service/search-java/src/cc/search/service/app/SearchAppCommon.java @@ -75,8 +75,7 @@ public abstract class SearchAppCommon implements AutoCloseable { /** * Logger. */ - private static final Logger _log = Logger.getLogger(SearchAppCommon.class - .getName()); + private static final Logger _log = Logger.getGlobal(); /** * Async task class for matching lines in a document. diff --git a/plugins/search/service/search-java/src/cc/search/service/app/query/QueryApp.java b/plugins/search/service/search-java/src/cc/search/service/app/query/QueryApp.java index b80a90aff..68fc2ef3b 100644 --- a/plugins/search/service/search-java/src/cc/search/service/app/query/QueryApp.java +++ b/plugins/search/service/search-java/src/cc/search/service/app/query/QueryApp.java @@ -1,6 +1,7 @@ package cc.search.service.app.query; import cc.search.service.app.SearchAppCommon; +import cc.search.common.FileLoggerInitializer; import cc.search.common.config.InvalidValueException; import cc.search.common.config.UnknownArgumentException; import cc.search.match.QueryContext; @@ -22,7 +23,7 @@ public class QueryApp extends SearchAppCommon { /** * Logger. */ - private static final Logger _log = Logger.getLogger(QueryApp.class.getName()); + private static final Logger _log = Logger.getGlobal(); /** * Application options. */ @@ -35,6 +36,7 @@ public class QueryApp extends SearchAppCommon { private QueryApp(QueryAppOptions options_) throws IOException { super(options_); _appOptions = options_; + FileLoggerInitializer.addFileOutput(options_, _log, "query"); } /** diff --git a/plugins/search/service/search-java/src/cc/search/service/app/service/SearchHandler.java b/plugins/search/service/search-java/src/cc/search/service/app/service/SearchHandler.java index 04ac6b763..383ef9618 100644 --- a/plugins/search/service/search-java/src/cc/search/service/app/service/SearchHandler.java +++ b/plugins/search/service/search-java/src/cc/search/service/app/service/SearchHandler.java @@ -49,8 +49,7 @@ abstract class SearchHandler extends SearchAppCommon /** * Logger. */ - private static final Logger _log = Logger.getLogger(SearchHandler.class - .getName()); + private static final Logger _log = Logger.getGlobal(); /** * Handler for suggestion requests. */ @@ -146,7 +145,7 @@ private SearchResult runSearch(QueryContext context_, SearchParams params_) */ public SearchHandler(CommonOptions options_) throws IOException { super(options_); - + Analyzer analyzer = new QueryAnalyzer(); _advDefQueryParser = new AdvancedTagQueryParser(analyzer); diff --git a/plugins/search/service/search-java/src/cc/search/service/app/service/ServiceApp.java b/plugins/search/service/search-java/src/cc/search/service/app/service/ServiceApp.java index 99ede1dca..e47ff6523 100644 --- a/plugins/search/service/search-java/src/cc/search/service/app/service/ServiceApp.java +++ b/plugins/search/service/search-java/src/cc/search/service/app/service/ServiceApp.java @@ -1,5 +1,6 @@ package cc.search.service.app.service; +import cc.search.common.FileLoggerInitializer; import cc.search.common.ipc.IPCProcessor; import cc.search.common.config.InvalidValueException; import cc.search.common.config.UnknownArgumentException; @@ -15,8 +16,7 @@ public class ServiceApp extends SearchHandler { /** * Logger. */ - private static final Logger _log = Logger.getLogger(ServiceApp.class - .getName()); + private static final Logger _log = Logger.getGlobal(); /** * IPC message processor. */ @@ -45,20 +45,26 @@ public void close() { } public static void main(String[] args_) { - _log.info("Search server started!"); - try { + // Initialize file logger + ServiceAppOptions options = new ServiceAppOptions(args_); + FileLoggerInitializer.addFileOutput(options, _log, "search"); + + _log.info("Search server started!"); try (ServiceApp app = - new ServiceApp(new ServiceAppOptions(args_))) { + new ServiceApp(options)) { _log.log(Level.INFO, "Start serving search for index {0}", app._options.indexDirPath); app._processor.serve(); - } catch (UnknownArgumentException | InvalidValueException | IOException e) { + } catch (IOException e) { _log.log(Level.SEVERE, "Fatal error!", e); System.exit(-1); } + } catch (UnknownArgumentException | InvalidValueException e) { + _log.log(Level.SEVERE, "Fatal error!", e); + System.exit(-1); } catch (Exception ex) { _log.log(Level.SEVERE, "Something bad happened :-(", ex); } finally { diff --git a/plugins/search/service/search-java/src/cc/search/suggestion/SuggestionHandler.java b/plugins/search/service/search-java/src/cc/search/suggestion/SuggestionHandler.java index a0f128e7c..45bde166d 100644 --- a/plugins/search/service/search-java/src/cc/search/suggestion/SuggestionHandler.java +++ b/plugins/search/service/search-java/src/cc/search/suggestion/SuggestionHandler.java @@ -25,8 +25,7 @@ public final class SuggestionHandler implements AutoCloseable { /** * Logger. */ - private static final Logger _log = Logger.getLogger(SuggestionHandler.class - .getName()); + private static final Logger _log = Logger.getGlobal(); /** * Filename suggester. */ diff --git a/plugins/search/service/src/searchservice.cpp b/plugins/search/service/src/searchservice.cpp index b83b6415d..a3ae32551 100644 --- a/plugins/search/service/src/searchservice.cpp +++ b/plugins/search/service/src/searchservice.cpp @@ -106,7 +106,10 @@ SearchServiceHandler::SearchServiceHandler( _db(db_) { _javaProcess.reset(new ServiceProcess(*datadir_ + "/search", - context_.compassRoot)); + context_.compassRoot, + context_.options.count("logtarget") + ? context_.options["logtarget"].as() + : "")); } void SearchServiceHandler::search( diff --git a/util/include/util/logutil.h b/util/include/util/logutil.h index 2127e7566..9b6a6cf1a 100644 --- a/util/include/util/logutil.h +++ b/util/include/util/logutil.h @@ -10,7 +10,11 @@ namespace cc namespace util { -void initLogger(); +void initConsoleLogger(); + +std::string getLoggingBase(const std::string& path_, const std::string& name_); + +bool initFileLogger(const std::string& path_); boost::log::trivial::severity_level getSeverityLevel(); diff --git a/util/src/logutil.cpp b/util/src/logutil.cpp index 445558856..60c7ac9ff 100644 --- a/util/src/logutil.cpp +++ b/util/src/logutil.cpp @@ -1,8 +1,12 @@ #include +#include #include #include #include +#include + +namespace fs = boost::filesystem; namespace cc { @@ -12,7 +16,21 @@ namespace util namespace { -void logFormatter( +BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime) + +std::string getFormattedTime(boost::posix_time::ptime ptime_) +{ + std::stringstream stream; + boost::posix_time::time_facet* facet = new boost::posix_time::time_facet(); + facet->format("%Y-%m-%d %H:%M:%S"); + stream.imbue(std::locale(std::locale::classic(), facet)); + + stream << ptime_; + + return stream.str(); +} + +void consoleLogFormatter( const boost::log::record_view& rec, boost::log::formatting_ostream& strm) { auto severity = rec[boost::log::trivial::severity]; @@ -40,7 +58,9 @@ void logFormatter( std::string sLevel = boost::log::trivial::to_string(severity.get()); std::transform(sLevel.begin(), sLevel.end(), sLevel.begin(), ::toupper); - strm << "[" << sLevel << "] " << rec[boost::log::expressions::smessage]; + std::string timeString = getFormattedTime(rec[timestamp].get()); + + strm << timeString << " [" << sLevel << "] " << rec[boost::log::expressions::smessage]; // Restore the default color if (severity) @@ -49,8 +69,21 @@ void logFormatter( } } +void fileLogFormatter( + const boost::log::record_view& rec, boost::log::formatting_ostream& strm) +{ + auto severity = rec[boost::log::trivial::severity]; + + std::string sLevel = boost::log::trivial::to_string(severity.get()); + std::transform(sLevel.begin(), sLevel.end(), sLevel.begin(), ::toupper); + + std::string timeString = getFormattedTime(rec[timestamp].get()); + + strm << timeString << " [" << sLevel << "] " << rec[boost::log::expressions::smessage]; } +} // namespace + boost::log::trivial::severity_level getSeverityLevel() { return boost::log::attribute_cast< @@ -58,13 +91,55 @@ boost::log::trivial::severity_level getSeverityLevel() boost::log::core::get()->get_global_attributes()["Severity"]).get(); } -void initLogger() +void initConsoleLogger() { + boost::log::add_common_attributes(); auto fsSink = boost::log::add_console_log( std::cout, boost::log::keywords::auto_flush = true); - fsSink->set_formatter(&logFormatter); + fsSink->set_formatter(&consoleLogFormatter); +} + +std::string getLoggingBase(const std::string& path_, const std::string& name_) +{ + if (path_.find('~') != std::string::npos) + { + throw std::invalid_argument("The path should not contain a \'~\' character. \ + Please provide an absolute path"); + } + + boost::system::error_code ec; + fs::create_directory(path_, ec); + if (ec) + { + throw std::invalid_argument("Permission denied to create " + path_); + } + + const std::string fullpath = canonical(absolute(fs::path(path_))).string(); + + return fullpath + (fullpath.back() == '/' ? "" : "/") + name_ + '_'; +} + +bool initFileLogger(const std::string& path_) +{ + auto fsSink = boost::log::add_file_log( + boost::log::keywords::file_name = path_, + boost::log::keywords::auto_flush = true + ); + fsSink->set_formatter(&fileLogFormatter); + try + { + // check if logging to file is possible + LOG(info) << "Start logging in file: " << path_; + } + catch(...) + { + boost::log::core::get()->remove_sink(fsSink); + LOG(warning) << "Could not open file for logging: " << path_; + return false; + } + return true; } } // util diff --git a/webserver/src/webserver.cpp b/webserver/src/webserver.cpp index c0df38c42..a6deabaf8 100644 --- a/webserver/src/webserver.cpp +++ b/webserver/src/webserver.cpp @@ -37,6 +37,9 @@ po::options_description commandLineArguments() po::value()->default_value(trivial::info), "Logging level of the parser. Possible values are: debug, info, warning, " "error, critical") + ("logtarget", po::value(), + "This is the path to the folder where the logging output files will be written. " + "If omitted, the output will be on the console only.") ("jobs,j", po::value()->default_value(4), "Number of worker threads."); @@ -51,7 +54,7 @@ int main(int argc, char* argv[]) const std::string SERVICE_PLUGIN_DIR = compassRoot + "/lib/serviceplugin"; const std::string WEBGUI_DIR = compassRoot + "/share/codecompass/webgui/"; - cc::util::initLogger(); + cc::util::initConsoleLogger(); MainRequestHandler requestHandler; requestHandler.pluginHandler.addDirectory(SERVICE_PLUGIN_DIR); @@ -67,6 +70,18 @@ int main(int argc, char* argv[]) po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); + if (vm.count("logtarget")) + { + vm.at("logtarget").value() = cc::util::getLoggingBase( vm["logtarget"].as() + , "CodeCompass" + ); + + if (!cc::util::initFileLogger(vm["logtarget"].as() + "webserver.log")) + { + vm.at("logtarget").value() = std::string(); + } + } + if (argc < 2 || vm.count("help")) { std::cout << desc << std::endl;