Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/util/output/LogWriter.cc @ 11520

Last change on this file since 11520 was 11071, checked in by landauf, 9 years ago

merged branch cpp11_v3 back to trunk

  • Property svn:eol-style set to native
File size: 6.3 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      Reto Grieder
26 *
27 */
28
29/**
30    @file
31    @brief Implementation of the LogWriter singleton.
32*/
33
34#include "LogWriter.h"
35
36#include <ctime>
37#include <chrono>
38#include <cstdlib>
39
40#include "OutputManager.h"
41#include "MemoryWriter.h"
42#include "util/Convert.h"
43
44namespace orxonox
45{
46    static constexpr int MAX_ARCHIVED_FILES = 9;
47
48    /**
49        @brief Constructor, initializes the desired output levels and the name and path of the log-file, and opens the log-file.
50
51        By default, LogWriter receives all output up to level::internal_info.
52        The log-file has a default name which usually doesn't change. The path
53        is initialized with a temporary directory, depending on the system,
54        and can be changed later.
55    */
56    LogWriter::LogWriter() : BaseWriter("Log")
57    {
58        this->setLevelMax(level::internal_info);
59
60        this->filename_ = "orxonox.log";
61
62        // get the path for a temporary file, depending on the system
63#ifdef ORXONOX_PLATFORM_WINDOWS
64        this->directory_ = getenv("TEMP");
65#else
66        this->directory_ = "/tmp";
67#endif
68
69        // send a message to the user so that he can find the file in the case of a crash.
70        OutputManager::getInstance().pushMessage(level::user_info, context::undefined(), "Opening log file " + this->getPath());
71
72        this->openFile();
73    }
74
75    /**
76        @brief Destructor, closes the log-file.
77    */
78    LogWriter::~LogWriter()
79    {
80        this->closeFile();
81    }
82
83    /**
84        @brief Opens the log-file in order to write output to it.
85    */
86    void LogWriter::openFile()
87    {
88        // archive the old log file
89        this->archive();
90
91        // open the file
92        this->file_.open(this->getPath().c_str(), std::fstream::out);
93
94        // check if it worked and print some output
95        if (this->file_.is_open())
96            this->printLine("Log file opened", level::none);
97        else
98            OutputManager::getInstance().pushMessage(level::user_warning, context::undefined(), "Failed to open log file. File logging disabled.");
99    }
100
101    /**
102        @brief Closes the log-file.
103    */
104    void LogWriter::closeFile()
105    {
106        if (this->file_.is_open())
107        {
108            this->printLine("Log file closed", level::none);
109            this->file_.close();
110        }
111    }
112
113    /**
114     * @brief Archives old copies of the log file by adding increasing numbers to the filename.
115     */
116    void LogWriter::archive(int index)
117    {
118        std::string oldPath = this->getArchivedPath(index);
119
120        // see if the file already exists, otherwise return
121        std::ifstream stream(oldPath.c_str());
122        bool exists = stream.is_open();
123        stream.close();
124
125        if (!exists)
126            return;
127
128        if (index < MAX_ARCHIVED_FILES)
129        {
130            // increment the index and archive the file with the next higher index
131            this->archive(++index);
132
133            // create the new path based on the incremented index
134            std::string newPath = this->getArchivedPath(index);
135
136            // move the file
137            std::rename(oldPath.c_str(), newPath.c_str());
138        }
139        else
140        {
141            // delete the file
142            std::remove(oldPath.c_str());
143        }
144    }
145   
146    /**
147     * @brief Returns the path for archived copies of the logfile (based on the archive index)
148     */
149    std::string LogWriter::getArchivedPath(int index) const
150    {
151        std::string path = this->getPath();
152        if (index > 0)
153            path += '.' + multi_cast<std::string>(index);
154        return path;
155    }
156
157    /**
158        @brief Changes the path of the log-file. Re-writes the log-file by using MemoryWriter.
159    */
160    void LogWriter::setLogDirectory(const std::string& directory)
161    {
162        // notify about the change of the log-file (because the old file will no longer be updated)
163        OutputManager::getInstance().pushMessage(level::internal_info, context::undefined(), "Migrating log file from " + this->directory_ + "\nto " + directory);
164
165        // close the old file, update the path and open the new file
166        this->closeFile();
167        this->directory_ = directory;
168        this->openFile();
169
170        // request old output from MemoryWriter
171        if (OutputManager::getInstance().getMemoryWriter())
172            OutputManager::getInstance().getMemoryWriter()->resendOutput(this);
173    }
174
175    /**
176        @brief Inherited function from BaseWriter, writers output together with a timestamp to the log-file.
177    */
178    void LogWriter::printLine(const std::string& line, OutputLevel)
179    {
180        if (!this->file_.is_open())
181            return;
182
183        // get the milliseconds
184        std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
185        std::chrono::system_clock::duration timeSinceEpoch = now.time_since_epoch();
186        std::chrono::milliseconds millisSinceEpoch = std::chrono::duration_cast<std::chrono::milliseconds>(timeSinceEpoch);
187        unsigned int millis = (millisSinceEpoch.count() % 1000);
188
189        // get the current time
190        time_t rawtime = std::chrono::system_clock::to_time_t(now);
191        struct tm* timeinfo = localtime(&rawtime);
192
193        // format time: hh:mm:ss:xxx
194        char buffer[13];
195        snprintf(buffer, sizeof(buffer), "%.2i:%.2i:%.2i:%.3i", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, millis);
196
197        // print timestamp and output line to the log file
198        this->file_ << buffer << ' ' << line << std::endl;
199    }
200}
Note: See TracBrowser for help on using the repository browser.