1 /******************************************************************************
2 * Copyright (c) 2011, Howard Butler, hobu.inc@gmail.com
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following
8 * conditions are met:
9 *
10 *     * Redistributions of source code must retain the above copyright
11 *       notice, this list of conditions and the following disclaimer.
12 *     * Redistributions in binary form must reproduce the above copyright
13 *       notice, this list of conditions and the following disclaimer in
14 *       the documentation and/or other materials provided
15 *       with the distribution.
16 *     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
17 *       names of its contributors may be used to endorse or promote
18 *       products derived from this software without specific prior
19 *       written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 * OF SUCH DAMAGE.
33 ****************************************************************************/
34 
35 #pragma once
36 
37 #include <cassert>
38 #include <memory> // shared_ptr
39 #include <stack>
40 #include <chrono>
41 
42 #include <pdal/pdal_internal.hpp>
43 #include <pdal/util/NullOStream.hpp>
44 
45 // Adapted from http://drdobbs.com/cpp/201804215
46 
47 namespace pdal
48 {
49 class Log;
50 
51 typedef std::shared_ptr<Log> LogPtr;
52 
53 /// pdal::Log is a logging object that is provided by pdal::Stage to
54 /// facilitate logging operations.
55 class PDAL_DLL Log
56 {
57 private:
58     /// Constructs a pdal::Log instance.
59     /// @param leaderString A string to presage all log entries with
60     /// @param outputName A filename or one of 'stdout', 'stdlog', or 'stderr'
61     ///                   to use for outputting log information.
62     /// @param timing Set to true to get timing output with log messages.
63     Log(std::string const& leaderString, std::string const& outputName,
64         bool timing = false);
65 
66     /// Constructs a pdal::Log instance.
67     /// @param leaderString A string to presage all log entries with
68     /// @param v An existing std::ostream to use for logging (instead of the
69     ///          the instance creating its own)
70     /// @param timing Set to true to get timing output with log messages.
71     Log(std::string const& leaderString, std::ostream* v, bool timing = false);
72 
73 public:
74     static LogPtr makeLog(std::string const& leaderString,
75         std::string const& outputName, bool timing = false);
76 
77     static LogPtr makeLog(std::string const& leaderString,
78         std::ostream* v, bool timing = false);
79 
80     /** @name Destructor
81     */
82     /// The destructor will clean up its own internal log stream, but it will
83     /// not touch one that is given via the constructor
84     ~Log();
85 
86     /** @name Logging level
87     */
88     /// @return the logging level of the pdal::Log instance
getLevel()89     LogLevel getLevel()
90     {
91         return m_level;
92     }
93 
94     /// Sets the logging level of the pdal::Log instance
95     /// @param v logging level to use for get() comparison operations
setLevel(LogLevel v)96     void setLevel(LogLevel v)
97     {
98         assert(v != LogLevel::None);
99         m_level = v;
100     }
101 
102     /// Set the leader string (deprecated).
103     /// \param[in]  leader  Leader string.
setLeader(const std::string & leader)104     void setLeader(const std::string& leader)
105         { pushLeader(leader); }
106 
107     /// Push the leader string onto the stack.
108     /// \param  leader  Leader string
pushLeader(const std::string & leader)109     void pushLeader(const std::string& leader)
110         { m_leaders.push(leader); }
111 
112     /// Get the leader string.
113     /// \return  The current leader string.
leader() const114     std::string leader() const
115         { return m_leaders.empty() ? std::string() : m_leaders.top(); }
116 
117     /// Pop the current leader string.
popLeader()118     void popLeader()
119     {
120         if (!m_leaders.empty())
121             m_leaders.pop();
122     }
123 
124     /// @return A string representing the LogLevel
125     std::string getLevelString(LogLevel v) const;
126 
127     /** @name Log stream operations
128     */
129     /// @return the stream object that is currently being used to for log
130     /// operations regardless of logging level of the instance.
getLogStream()131     std::ostream* getLogStream()
132     {
133         return m_log;
134     }
135 
136     /// Returns the log stream given the logging level.
137     /// @param level logging level to request
138     /// If the logging level asked for with
139     /// pdal::Log::get is less than the logging level of the pdal::Log instance
140     std::ostream& get(LogLevel level = LogLevel::Info);
141 
142     /// Sets the floating point precision
143     void floatPrecision(int level);
144 
145     /// Clears the floating point precision settings of the streams
146     void clearFloat();
147 
148 protected:
149     std::ostream *m_log;
150 
151 private:
152     Log(const Log&) = delete;
153     Log& operator =(const Log&) = delete;
154     std::string now() const;
155 
156     LogLevel m_level;
157     bool m_deleteStreamOnCleanup;
158     std::stack<std::string> m_leaders;
159     NullOStream m_nullStream;
160     bool m_timing;
161     std::chrono::steady_clock m_clock;
162     std::chrono::steady_clock::time_point m_start;
163 };
164 
165 } // namespace pdal
166 
167