1 /*
2 * PCMSolver, an API for the Polarizable Continuum Model
3 * Copyright (C) 2020 Roberto Di Remigio, Luca Frediani and contributors.
4 *
5 * This file is part of PCMSolver.
6 *
7 * PCMSolver is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * PCMSolver is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with PCMSolver. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * For information on the complete list of contributors to the
21 * PCMSolver API, see: <http://pcmsolver.readthedocs.io/>
22 */
23
24 #pragma once
25
26 #include <ctime>
27 #include <mutex>
28 #include <sstream>
29 #include <string>
30
31 #include "LoggerImpl.hpp"
32
33 namespace logging {
34 std::string getTime();
35
36 template <typename logPolicy> class logger {
37 private:
38 printLevel globalPrintLevel_;
39 std::stringstream logStream_;
40 logPolicy * policy_;
41 std::mutex writeMutex_;
42
43 /*! @name Core printing functionality
44 *
45 * A variadic template is used, we specify the version
46 * with a variable number of parameters/types and the version
47 * with no parameters/types.
48 * The variadic template is called recursively.
49 * The type for the first parameter is resolved and streamed
50 * to logStream_. When all the parameters have been streamed
51 * the version with no arguments is called.
52 */
53 /// @{
54 /*! */
printImpl()55 void printImpl() {
56 policy_->write(logStream_.str());
57 logStream_.str("");
58 }
59 template <typename First, typename... Rest>
printImpl(First parm1,Rest...parm)60 void printImpl(First parm1, Rest... parm) {
61 logStream_.precision(std::numeric_limits<double>::digits10);
62 logStream_ << parm1 << std::endl;
63 printImpl(parm...);
64 }
65 /// @}
66 public:
67 /*! Constructor
68 * \param[in] name name for the log file
69 * The build parameters are logged first
70 */
logger(const std::string & name,printLevel print=coarse)71 logger(const std::string & name, printLevel print = coarse)
72 : globalPrintLevel_(print), policy_(new logPolicy) {
73 if (!policy_) {
74 PCMSOLVER_ERROR("LOGGER: Unable to create the logger instance");
75 }
76 policy_->open_ostream(name);
77 // Write the logfile header
78 logStream_ << "\t\tPCMSolver execution log\n"
79 << buildInfo() << "\n\t\tLog started : " << getTime() << std::endl;
80 }
81 /// Destructor
~logger()82 ~logger() {
83 if (policy_) {
84 policy_->close_ostream();
85 delete policy_;
86 }
87 }
88
globalPrintLevel(int printLvl)89 void globalPrintLevel(int printLvl) { globalPrintLevel_ = printLvl; }
90
91 /// User interface for the logger class
print(Args...args)92 template <printLevel printLvl, typename... Args> void print(Args... args) {
93 if (globalPrintLevel_ >= printLvl) {
94 writeMutex_.lock();
95 printImpl(args...);
96 writeMutex_.unlock();
97 }
98 }
99 };
100
101 /*! \brief Returns date and time */
getTime()102 inline std::string getTime() {
103 std::string time_str;
104 time_t raw_time;
105
106 std::time(&raw_time);
107 time_str = std::ctime(&raw_time);
108
109 // Without the newline character
110 return time_str;
111 }
112
113 } // namespace logging
114