TrinityCore
AppenderFile.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "AppenderFile.h"
19#include "Log.h"
20#include "LogMessage.h"
21#include "StringConvert.h"
22#include <algorithm>
23
24AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& args) :
25 Appender(id, name, level, flags),
26 logfile(nullptr),
27 _logDir(sLog->GetLogsDir()),
28 _maxFileSize(0),
29 _fileSize(0)
30{
31 if (args.size() < 4)
32 throw InvalidAppenderArgsException(Trinity::StringFormat("Log::CreateAppenderFromConfig: Missing file name for appender {}", name));
33
34 _fileName.assign(args[3]);
35
36 std::string mode = "a";
37 if (4 < args.size())
38 mode.assign(args[4]);
39
41 {
42 size_t dot_pos = _fileName.find_last_of('.');
43 if (dot_pos != std::string::npos)
44 _fileName.insert(dot_pos, sLog->GetLogsTimestamp());
45 else
46 _fileName += sLog->GetLogsTimestamp();
47 }
48
49 if (5 < args.size())
50 {
51 if (Optional<uint32> size = Trinity::StringTo<uint32>(args[5]))
53 else
54 throw InvalidAppenderArgsException(Trinity::StringFormat("Log::CreateAppenderFromConfig: Invalid size '{}' for appender {}", args[5], name));
55 }
56
57 _dynamicName = std::string::npos != _fileName.find("%s");
59
60 if (!_dynamicName)
61 logfile = OpenFile(_fileName, mode, (mode == "w") && _backup);
62}
63
65{
66 CloseFile();
67}
68
69void AppenderFile::_write(LogMessage const* message)
70{
71 bool exceedMaxSize = _maxFileSize > 0 && (_fileSize.load() + message->Size()) > _maxFileSize;
72
73 if (_dynamicName)
74 {
75 char namebuf[TRINITY_PATH_MAX];
76 snprintf(namebuf, TRINITY_PATH_MAX, _fileName.c_str(), message->param1.c_str());
77 // always use "a" with dynamic name otherwise it could delete the log we wrote in last _write() call
78 FILE* file = OpenFile(namebuf, "a", _backup || exceedMaxSize);
79 if (!file)
80 return;
81 fprintf(file, "%s%s\n", message->prefix.c_str(), message->text.c_str());
82 fflush(file);
83 _fileSize += uint64(message->Size());
84 fclose(file);
85 return;
86 }
87 else if (exceedMaxSize)
88 logfile = OpenFile(_fileName, "w", true);
89
90 if (!logfile)
91 return;
92
93 fprintf(logfile, "%s%s\n", message->prefix.c_str(), message->text.c_str());
94 fflush(logfile);
95 _fileSize += uint64(message->Size());
96}
97
98FILE* AppenderFile::OpenFile(std::string const& filename, std::string const& mode, bool backup)
99{
100 std::string fullName(_logDir + filename);
101 if (backup)
102 {
103 CloseFile();
104 std::string newName(fullName);
105 newName.push_back('.');
106 newName.append(LogMessage::getTimeStr(time(nullptr)));
107 std::replace(newName.begin(), newName.end(), ':', '-');
108 rename(fullName.c_str(), newName.c_str()); // no error handling... if we couldn't make a backup, just ignore
109 }
110
111 if (FILE* ret = fopen(fullName.c_str(), mode.c_str()))
112 {
113 _fileSize = ftell(ret);
114 return ret;
115 }
116
117 return nullptr;
118}
119
121{
122 if (logfile)
123 {
124 fclose(logfile);
125 logfile = nullptr;
126 }
127}
uint8_t uint8
Definition: Define.h:144
#define TRINITY_PATH_MAX
Definition: Define.h:63
uint64_t uint64
Definition: Define.h:141
uint16 flags
Definition: DisableMgr.cpp:49
AppenderFlags
Definition: LogCommon.h:50
@ APPENDER_FLAGS_MAKE_FILE_BACKUP
Definition: LogCommon.h:56
@ APPENDER_FLAGS_USE_TIMESTAMP
Definition: LogCommon.h:55
LogLevel
Definition: LogCommon.h:25
#define sLog
Definition: Log.h:130
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
std::atomic< uint64 > _fileSize
Definition: AppenderFile.h:43
AppenderFile(uint8 id, std::string const &name, LogLevel level, AppenderFlags flags, std::vector< std::string_view > const &args)
bool _dynamicName
Definition: AppenderFile.h:40
uint64 _maxFileSize
Definition: AppenderFile.h:42
void _write(LogMessage const *message) override
std::string _fileName
Definition: AppenderFile.h:38
FILE * logfile
Definition: AppenderFile.h:37
std::string _logDir
Definition: AppenderFile.h:39
FILE * OpenFile(std::string const &name, std::string const &mode, bool backup)
std::string name
Definition: Appender.h:50
AppenderFlags flags
Definition: Appender.h:52
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
Definition: StringFormat.h:38
constexpr std::size_t size()
Definition: UpdateField.h:796
std::string const text
Definition: LogMessage.h:39
std::string getTimeStr() const
Definition: LogMessage.cpp:39
uint32 Size() const
@ Returns size of the log message content in bytes
Definition: LogMessage.h:45
std::string param1
Definition: LogMessage.h:41
std::string prefix
Definition: LogMessage.h:40