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