Core/Log: Add type safe formatting

* improves safety and log speed through:
  - variadic templates
  - perfect forwarding
* fixes a newline in db logs
* improve performance of Appender::write by using std::ostringstream && std::move
This commit is contained in:
Naios
2015-03-11 10:06:24 +01:00
parent a860c62fed
commit 95ebe4f31c
34 changed files with 5003 additions and 147 deletions

View File

@@ -35,6 +35,7 @@ if(SERVERS OR TOOLS)
endif()
if(SERVERS)
add_subdirectory(cppformat)
add_subdirectory(gsoap)
add_subdirectory(zmqpp)
endif()

View File

@@ -8,6 +8,10 @@ bzip2 (a freely available, patent free, high-quality data compressor)
http://www.bzip.org/
Version: 1.0.6
cppformat (type safe format library)
https://github.com/cppformat/cppformat
Version: 1.1.0 da547f5533f338cc0c65877b44ca40adf31754f7
G3D (a commercial-grade C++ 3D engine available as Open Source (BSD License)
http://g3d.sourceforge.net/
Version: 9.0-Release r4036

View File

@@ -0,0 +1,35 @@
include(CheckCXXCompilerFlag)
include(CheckSymbolExists)
set(FMT_SOURCES format.cc format.h)
if (CMAKE_COMPILER_IS_GNUCXX)
set_target_properties(format PROPERTIES COMPILE_FLAGS
"-Wall -Wextra -Wshadow -pedantic")
endif ()
# Use variadic templates
add_definitions(-DFMT_VARIADIC_TEMPLATES=1)
# Check if initializer lists are supported.
check_cxx_source_compiles("
#include <initilizer_list>
int main() {}" FMT_INITIALIZER_LIST)
# Use delete
add_definitions(-DFMT_USE_DELETED_FUNCTIONS=1)
# Use static assert
add_definitions(-DFMT_USE_STATIC_ASSERT=1)
if (WIN32)
check_symbol_exists(open io.h HAVE_OPEN)
else ()
check_symbol_exists(open fcntl.h HAVE_OPEN)
endif ()
if (HAVE_OPEN)
add_definitions(-DFMT_USE_FILE_DESCRIPTORS=1)
set(FMT_SOURCES ${FMT_SOURCES} posix.cc posix.h)
endif ()
add_library(format STATIC ${FMT_SOURCES})

335
dep/cppformat/ChangeLog.rst Normal file
View File

@@ -0,0 +1,335 @@
1.1.0 - 2015-03-06
------------------
* Added ``BasicArrayWriter``, a class template that provides operations for
formatting and writing data into a fixed-size array
(`#105 <https://github.com/cppformat/cppformat/issues/105>`_ and
`#122 <https://github.com/cppformat/cppformat/issues/122>`_):
.. code:: c++
char buffer[100];
fmt::ArrayWriter w(buffer);
w.write("The answer is {}", 42);
* Added `0 A.D. <http://play0ad.com/>`_ and `PenUltima Online (POL)
<http://www.polserver.com/>`_ to the list of notable projects using C++ Format.
* C++ Format now uses MSVC intrinsics for better formatting performance
(`#115 <https://github.com/cppformat/cppformat/pull/115>`_,
`#116 <https://github.com/cppformat/cppformat/pull/116>`_,
`#118 <https://github.com/cppformat/cppformat/pull/118>`_ and
`#121 <https://github.com/cppformat/cppformat/pull/121>`_).
Previously these optimizations where only used on GCC and Clang.
Thanks to `@CarterLi <https://github.com/CarterLi>`_ and
`@objectx <https://github.com/objectx>`_.
* CMake install target (`#119 <https://github.com/cppformat/cppformat/pull/119>`_).
Thanks to `@TrentHouliston <https://github.com/TrentHouliston>`_.
You can now install C++ Format with ``make install`` command.
* Improved `Biicode <http://www.biicode.com/>`_ support
(`#98 <https://github.com/cppformat/cppformat/pull/98>`_ and
`#104 <https://github.com/cppformat/cppformat/pull/104>`_). Thanks to
`@MariadeAnton <https://github.com/MariadeAnton>`_ and
`@franramirez688 <https://github.com/franramirez688>`_.
* Improved support for bulding with `Android NDK
<https://developer.android.com/tools/sdk/ndk/index.html>`_
(`#107 <https://github.com/cppformat/cppformat/pull/107>`_).
Thanks to `@newnon <https://github.com/newnon>`_.
The `android-ndk-example <https://github.com/cppformat/android-ndk-example>`_
repository provides and example of using C++ Format with Android NDK:
.. image:: https://raw.githubusercontent.com/cppformat/android-ndk-example/
master/screenshot.png
* Improved documentation of ``SystemError`` and ``WindowsError``
(`#54 <https://github.com/cppformat/cppformat/issues/54>`_).
* Various code improvements
(`#110 <https://github.com/cppformat/cppformat/pull/110>`_,
`#111 <https://github.com/cppformat/cppformat/pull/111>`_
`#112 <https://github.com/cppformat/cppformat/pull/112>`_).
Thanks to `@CarterLi <https://github.com/CarterLi>`_.
* Improved compile-time errors when formatting wide into narrow strings
(`#117 <https://github.com/cppformat/cppformat/issues/117>`_).
* Fixed ``BasicWriter::write`` without formatting arguments when C++11 support
is disabled (`#109 <https://github.com/cppformat/cppformat/issues/109>`_).
* Fixed header-only build on OS X with GCC 4.9
(`#124 <https://github.com/cppformat/cppformat/issues/124>`_).
* Fixed packaging issues (`#94 <https://github.com/cppformat/cppformat/issues/94>`_).
* Fixed warnings in GCC, MSVC and Xcode/Clang
(`#95 <https://github.com/cppformat/cppformat/issues/95>`_,
`#96 <https://github.com/cppformat/cppformat/issues/96>`_ and
`#114 <https://github.com/cppformat/cppformat/pull/114>`_).
* Added `changelog <https://github.com/cppformat/cppformat/edit/master/ChangeLog.rst>`_
(`#103 <https://github.com/cppformat/cppformat/issues/103>`_).
1.0.0 - 2015-02-05
------------------
* Add support for a header-only configuration when ``FMT_HEADER_ONLY`` is
defined before including ``format.h``:
.. code:: c++
#define FMT_HEADER_ONLY
#include "format.h"
* Compute string length in the constructor of ``BasicStringRef``
instead of the ``size`` method
(`#79 <https://github.com/cppformat/cppformat/issues/79>`_).
This eliminates size computation for string literals on reasonable optimizing
compilers.
* Fix formatting of types with overloaded ``operator <<`` for ``std::wostream``
(`#86 <https://github.com/cppformat/cppformat/issues/86>`_):
.. code:: c++
fmt::format(L"The date is {0}", Date(2012, 12, 9));
* Fix linkage of tests on Arch Linux
(`#89 <https://github.com/cppformat/cppformat/issues/89>`_).
* Allow precision specifier for non-float arguments
(`#90 <https://github.com/cppformat/cppformat/issues/90>`_):
.. code:: c++
fmt::print("{:.3}\n", "Carpet"); // prints "Car"
* Fix build on Android NDK
(`#93 <https://github.com/cppformat/cppformat/issues/93>`_)
* Improvements to documentation build procedure.
* Remove ``FMT_SHARED`` CMake variable in favor of standard `BUILD_SHARED_LIBS
<http://www.cmake.org/cmake/help/v3.0/variable/BUILD_SHARED_LIBS.html>`_.
* Fix error handling in ``fmt::fprintf``.
* Fix a number of warnings.
0.12.0 - 2014-10-25
-------------------
* [Breaking] Improved separation between formatting and buffer management.
``Writer`` is now a base class that cannot be instantiated directly.
The new ``MemoryWriter`` class implements the default buffer management
with small allocations done on stack. So ``fmt::Writer`` should be replaced
with ``fmt::MemoryWriter`` in variable declarations.
Old code:
.. code:: c++
fmt::Writer w;
New code:
.. code:: c++
fmt::MemoryWriter w;
If you pass ``fmt::Writer`` by reference, you can continue to do so:
.. code:: c++
void f(fmt::Writer &w);
This doesn't affect the formatting API.
* Support for custom memory allocators
(`#69 <https://github.com/cppformat/cppformat/issues/69>`_)
* Formatting functions now accept `signed char` and `unsigned char` strings as
arguments (`#73 <https://github.com/cppformat/cppformat/issues/73>`_):
.. code:: c++
auto s = format("GLSL version: {}", glGetString(GL_VERSION));
* Reduced code bloat. According to the new `benchmark results
<https://github.com/cppformat/cppformat#compile-time-and-code-bloat>`_,
cppformat is close to ``printf`` and by the order of magnitude better than
Boost Format in terms of compiled code size.
* Improved appearance of the documentation on mobile by using the `Sphinx
Bootstrap theme <http://ryan-roemer.github.io/sphinx-bootstrap-theme/>`_:
.. |old| image:: https://cloud.githubusercontent.com/assets/576385/4792130/
cd256436-5de3-11e4-9a62-c077d0c2b003.png
.. |new| image:: https://cloud.githubusercontent.com/assets/576385/4792131/
cd29896c-5de3-11e4-8f59-cac952942bf0.png
+-------+-------+
| Old | New |
+-------+-------+
| |old| | |new| |
+-------+-------+
0.11.0 - 2014-08-21
-------------------
* Safe printf implementation with a POSIX extension for positional arguments:
.. code:: c++
fmt::printf("Elapsed time: %.2f seconds", 1.23);
fmt::printf("%1$s, %3$d %2$s", weekday, month, day);
* Arguments of ``char`` type can now be formatted as integers
(Issue `#55 <https://github.com/cppformat/cppformat/issues/55>`_):
.. code:: c++
fmt::format("0x{0:02X}", 'a');
* Deprecated parts of the API removed.
* The library is now built and tested on MinGW with Appveyor in addition to
existing test platforms Linux/GCC, OS X/Clang, Windows/MSVC.
0.10.0 - 2014-07-01
-------------------
**Improved API**
* All formatting methods are now implemented as variadic functions instead
of using ``operator<<`` for feeding arbitrary arguments into a temporary
formatter object. This works both with C++11 where variadic templates are
used and with older standards where variadic functions are emulated by
providing lightweight wrapper functions defined with the ``FMT_VARIADIC``
macro. You can use this macro for defining your own portable variadic
functions:
.. code:: c++
void report_error(const char *format, const fmt::ArgList &args) {
fmt::print("Error: {}");
fmt::print(format, args);
}
FMT_VARIADIC(void, report_error, const char *)
report_error("file not found: {}", path);
Apart from a more natural syntax, this also improves performance as there
is no need to construct temporary formatter objects and control arguments'
lifetimes. Because the wrapper functions are very ligthweight, this doesn't
cause code bloat even in pre-C++11 mode.
* Simplified common case of formatting an ``std::string``. Now it requires a
single function call:
.. code:: c++
std::string s = format("The answer is {}.", 42);
Previously it required 2 function calls:
.. code:: c++
std::string s = str(Format("The answer is {}.") << 42);
Instead of unsafe ``c_str`` function, ``fmt::Writer`` should be used directly
to bypass creation of ``std::string``:
.. code:: c++
fmt::Writer w;
w.write("The answer is {}.", 42);
w.c_str(); // returns a C string
This doesn't do dynamic memory allocation for small strings and is less error
prone as the lifetime of the string is the same as for ``std::string::c_str``
which is well understood (hopefully).
* Improved consistency in naming functions that are a part of the public API.
Now all public functions are lowercase following the standard library
conventions. Previously it was a combination of lowercase and
CapitalizedWords.
Issue `#50 <https://github.com/cppformat/cppformat/issues/50>`_.
* Old functions are marked as deprecated and will be removed in the next
release.
**Other Changes**
* Experimental support for printf format specifications (work in progress):
.. code:: c++
fmt::printf("The answer is %d.", 42);
std::string s = fmt::sprintf("Look, a %s!", "string");
* Support for hexadecimal floating point format specifiers ``a`` and ``A``:
.. code:: c++
print("{:a}", -42.0); // Prints -0x1.5p+5
print("{:A}", -42.0); // Prints -0X1.5P+5
* CMake option ``FMT_SHARED`` that specifies whether to build format as a
shared library (off by default).
0.9.0 - 2014-05-13
------------------
* More efficient implementation of variadic formatting functions.
* ``Writer::Format`` now has a variadic overload:
.. code:: c++
Writer out;
out.Format("Look, I'm {}!", "variadic");
* For efficiency and consistency with other overloads, variadic overload of
the ``Format`` function now returns ``Writer`` instead of ``std::string``.
Use the ``str`` function to convert it to ``std::string``:
.. code:: c++
std::string s = str(Format("Look, I'm {}!", "variadic"));
* Replaced formatter actions with output sinks: ``NoAction`` -> ``NullSink``,
``Write`` -> ``FileSink``, ``ColorWriter`` -> ``ANSITerminalSink``.
This improves naming consistency and shouldn't affect client code unless
these classes are used directly which should be rarely needed.
* Added ``ThrowSystemError`` function that formats a message and throws
``SystemError`` containing the formatted message and system-specific error
description. For example, the following code
.. code:: c++
FILE *f = fopen(filename, "r");
if (!f)
ThrowSystemError(errno, "Failed to open file '{}'") << filename;
will throw ``SystemError`` exception with description
"Failed to open file '<filename>': No such file or directory" if file
doesn't exist.
* Support for AppVeyor continuous integration platform.
* ``Format`` now throws ``SystemError`` in case of I/O errors.
* Improve test infrastructure. Print functions are now tested by redirecting
the output to a pipe.
0.8.0 - 2014-04-14
------------------
* Initial release

22
dep/cppformat/LICENSE Normal file
View File

@@ -0,0 +1,22 @@
Copyright (c) 2014 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

1175
dep/cppformat/format.cc Normal file

File diff suppressed because it is too large Load Diff

2679
dep/cppformat/format.h Normal file

File diff suppressed because it is too large Load Diff

242
dep/cppformat/posix.cc Normal file
View File

@@ -0,0 +1,242 @@
/*
A C++ interface to POSIX functions.
Copyright (c) 2014 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Disable bogus MSVC warnings.
#ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "posix.h"
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
# include <unistd.h>
#else
# include <windows.h>
# include <io.h>
# define O_CREAT _O_CREAT
# define O_TRUNC _O_TRUNC
#ifndef S_IRUSR
# define S_IRUSR _S_IREAD
#endif
#ifndef S_IWUSR
# define S_IWUSR _S_IWRITE
#endif
# ifdef __MINGW32__
# define _SH_DENYNO 0x40
# endif
#endif // _WIN32
namespace {
#ifdef _WIN32
// Return type of read and write functions.
typedef int RWResult;
// On Windows the count argument to read and write is unsigned, so convert
// it from size_t preventing integer overflow.
inline unsigned convert_rwcount(std::size_t count) {
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
}
#else
// Return type of read and write functions.
typedef ssize_t RWResult;
inline std::size_t convert_rwcount(std::size_t count) { return count; }
#endif
}
fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT {
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
fmt::report_system_error(errno, "cannot close file");
}
fmt::BufferedFile::BufferedFile(fmt::StringRef filename, fmt::StringRef mode) {
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0);
if (!file_)
throw SystemError(errno, "cannot open file {}", filename);
}
void fmt::BufferedFile::close() {
if (!file_)
return;
int result = FMT_SYSTEM(fclose(file_));
file_ = 0;
if (result != 0)
throw SystemError(errno, "cannot close file");
}
int fmt::BufferedFile::fileno() const {
int fd = FMT_POSIX_CALL(fileno(file_));
if (fd == -1)
throw SystemError(errno, "cannot get file descriptor");
return fd;
}
fmt::File::File(fmt::StringRef path, int oflag) {
int mode = S_IRUSR | S_IWUSR;
#ifdef _WIN32
fd_ = -1;
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
#else
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
#endif
if (fd_ == -1)
throw SystemError(errno, "cannot open file {}", path);
}
fmt::File::~File() FMT_NOEXCEPT {
// Don't retry close in case of EINTR!
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
fmt::report_system_error(errno, "cannot close file");
}
void fmt::File::close() {
if (fd_ == -1)
return;
// Don't retry close in case of EINTR!
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
int result = FMT_POSIX_CALL(close(fd_));
fd_ = -1;
if (result != 0)
throw SystemError(errno, "cannot close file");
}
fmt::LongLong fmt::File::size() const {
#ifdef _WIN32
LARGE_INTEGER filesize = {};
HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
if (!FMT_SYSTEM(GetFileSizeEx(handle, &filesize)))
throw WindowsError(GetLastError(), "cannot get file size");
FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(filesize.QuadPart),
"return type of File::size is not large enough");
return filesize.QuadPart;
#else
typedef struct stat Stat;
Stat file_stat = Stat();
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
throw SystemError(errno, "cannot get file attributes");
FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),
"return type of File::size is not large enough");
return file_stat.st_size;
#endif
}
std::size_t fmt::File::read(void *buffer, std::size_t count) {
RWResult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
if (result < 0)
throw SystemError(errno, "cannot read from file");
return result;
}
std::size_t fmt::File::write(const void *buffer, std::size_t count) {
RWResult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
if (result < 0)
throw SystemError(errno, "cannot write to file");
return result;
}
fmt::File fmt::File::dup(int fd) {
// Don't retry as dup doesn't return EINTR.
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
int new_fd = FMT_POSIX_CALL(dup(fd));
if (new_fd == -1)
throw SystemError(errno, "cannot duplicate file descriptor {}", fd);
return File(new_fd);
}
void fmt::File::dup2(int fd) {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) {
throw SystemError(errno,
"cannot duplicate file descriptor {} to {}", fd_, fd);
}
}
void fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1)
ec = ErrorCode(errno);
}
void fmt::File::pipe(File &read_end, File &write_end) {
// Close the descriptors first to make sure that assignments don't throw
// and there are no leaks.
read_end.close();
write_end.close();
int fds[2] = {};
#ifdef _WIN32
// Make the default pipe capacity same as on Linux 2.6.11+.
enum { DEFAULT_CAPACITY = 65536 };
int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
#else
// Don't retry as the pipe function doesn't return EINTR.
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
int result = FMT_POSIX_CALL(pipe(fds));
#endif
if (result != 0)
throw SystemError(errno, "cannot create pipe");
// The following assignments don't throw because read_fd and write_fd
// are closed.
read_end = File(fds[0]);
write_end = File(fds[1]);
}
fmt::BufferedFile fmt::File::fdopen(const char *mode) {
// Don't retry as fdopen doesn't return EINTR.
FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));
if (!f)
throw SystemError(errno, "cannot associate stream with file descriptor");
BufferedFile file(f);
fd_ = -1;
return file;
}
long fmt::getpagesize() {
#ifdef _WIN32
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwPageSize;
#else
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
if (size < 0)
throw SystemError(errno, "cannot get memory page size");
return size;
#endif
}

337
dep/cppformat/posix.h Normal file
View File

@@ -0,0 +1,337 @@
/*
A C++ interface to POSIX functions.
Copyright (c) 2014 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FMT_POSIX_H_
#define FMT_POSIX_H_
#include <errno.h>
#include <fcntl.h> // for O_RDONLY
#include <stdio.h>
#include <cstddef>
#include "format.h"
#ifdef FMT_INCLUDE_POSIX_TEST
# include "test/posix-test.h"
#endif
#ifndef FMT_POSIX
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX(call) _##call
# else
# define FMT_POSIX(call) call
# endif
#endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else
# define FMT_SYSTEM(call) call
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX_CALL(call) ::_##call
# else
# define FMT_POSIX_CALL(call) ::call
# endif
#endif
#if FMT_GCC_VERSION >= 407
# define FMT_UNUSED __attribute__((unused))
#else
# define FMT_UNUSED
#endif
#if FMT_USE_STATIC_ASSERT || FMT_HAS_CPP_ATTRIBUTE(cxx_static_assert) || \
(FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600
# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message)
#else
# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b)
# define FMT_STATIC_ASSERT(cond, message) \
typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
#endif
// Retries the expression while it evaluates to error_result and errno
// equals to EINTR.
#ifndef _WIN32
# define FMT_RETRY_VAL(result, expression, error_result) \
do { \
result = (expression); \
} while (result == error_result && errno == EINTR)
#else
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
namespace fmt {
// An error code.
class ErrorCode {
private:
int value_;
public:
explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {}
int get() const FMT_NOEXCEPT { return value_; }
};
// A buffered file.
class BufferedFile {
private:
FILE *file_;
friend class File;
explicit BufferedFile(FILE *f) : file_(f) {}
public:
// Constructs a BufferedFile object which doesn't represent any file.
BufferedFile() FMT_NOEXCEPT : file_(0) {}
// Destroys the object closing the file it represents if any.
~BufferedFile() FMT_NOEXCEPT;
#if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue
// references are not supported.
private:
// A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly.
struct Proxy {
FILE *file;
};
public:
// A "move constructor" for moving from a temporary.
BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
// A "move constructor" for for moving from an lvalue.
BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) {
f.file_ = 0;
}
// A "move assignment operator" for moving from a temporary.
BufferedFile &operator=(Proxy p) {
close();
file_ = p.file;
return *this;
}
// A "move assignment operator" for moving from an lvalue.
BufferedFile &operator=(BufferedFile &other) {
close();
file_ = other.file_;
other.file_ = 0;
return *this;
}
// Returns a proxy object for moving from a temporary:
// BufferedFile file = BufferedFile(...);
operator Proxy() FMT_NOEXCEPT {
Proxy p = {file_};
file_ = 0;
return p;
}
#else
private:
FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
public:
BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) {
other.file_ = 0;
}
BufferedFile& operator=(BufferedFile &&other) {
close();
file_ = other.file_;
other.file_ = 0;
return *this;
}
#endif
// Opens a file.
BufferedFile(fmt::StringRef filename, fmt::StringRef mode);
// Closes the file.
void close();
// Returns the pointer to a FILE object representing this file.
FILE *get() const FMT_NOEXCEPT { return file_; }
int fileno() const;
void print(fmt::StringRef format_str, const ArgList &args) {
fmt::print(file_, format_str, args);
}
FMT_VARIADIC(void, print, fmt::StringRef)
};
// A file. Closed file is represented by a File object with descriptor -1.
// Methods that are not declared with FMT_NOEXCEPT may throw
// fmt::SystemError in case of failure. Note that some errors such as
// closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler.
class File {
private:
int fd_; // File descriptor.
// Constructs a File object with a given descriptor.
explicit File(int fd) : fd_(fd) {}
public:
// Possible values for the oflag argument to the constructor.
enum {
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
};
// Constructs a File object which doesn't represent any file.
File() FMT_NOEXCEPT : fd_(-1) {}
// Opens a file and constructs a File object representing this file.
File(fmt::StringRef path, int oflag);
#if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue
// references are not supported.
private:
// A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly.
struct Proxy {
int fd;
};
public:
// A "move constructor" for moving from a temporary.
File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
// A "move constructor" for for moving from an lvalue.
File(File &other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1;
}
// A "move assignment operator" for moving from a temporary.
File &operator=(Proxy p) {
close();
fd_ = p.fd;
return *this;
}
// A "move assignment operator" for moving from an lvalue.
File &operator=(File &other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
// Returns a proxy object for moving from a temporary:
// File file = File(...);
operator Proxy() FMT_NOEXCEPT {
Proxy p = {fd_};
fd_ = -1;
return p;
}
#else
private:
FMT_DISALLOW_COPY_AND_ASSIGN(File);
public:
File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1;
}
File& operator=(File &&other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
#endif
// Destroys the object closing the file it represents if any.
~File() FMT_NOEXCEPT;
// Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; }
// Closes the file.
void close();
// Returns the file size.
fmt::LongLong size() const;
// Attempts to read count bytes from the file into the specified buffer.
std::size_t read(void *buffer, std::size_t count);
// Attempts to write count bytes from the specified buffer to the file.
std::size_t write(const void *buffer, std::size_t count);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
static File dup(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
void dup2(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
static void pipe(File &read_end, File &write_end);
// Creates a BufferedFile object associated with this file and detaches
// this File object from the file.
BufferedFile fdopen(const char *mode);
};
// Returns the memory page size.
long getpagesize();
} // namespace fmt
#if !FMT_USE_RVALUE_REFERENCES
namespace std {
// For compatibility with C++98.
inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; }
inline fmt::File &move(fmt::File &f) { return f; }
}
#endif
#endif // FMT_POSIX_H_

View File

@@ -45,6 +45,7 @@ endif()
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/zmqpp
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
@@ -87,6 +88,7 @@ target_link_libraries(bnetserver
ipc
shared
zmqpp
format
${MYSQL_LIBRARY}
${OPENSSL_LIBRARIES}
${ZMQ_LIBRARY}

View File

@@ -35,6 +35,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include
${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging

View File

@@ -110,6 +110,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/zlib
${CMAKE_SOURCE_DIR}/dep/zmqpp
${CMAKE_SOURCE_DIR}/src/server/collision

View File

@@ -106,17 +106,6 @@ ChatCommand* ChatHandler::getCommandTable()
return commandTableCache;
}
std::string ChatHandler::PGetParseString(uint32 entry, ...) const
{
const char *format = GetTrinityString(entry);
char str[1024];
va_list ap;
va_start(ap, entry);
vsnprintf(str, 1024, format, ap);
va_end(ap);
return std::string(str);
}
char const* ChatHandler::GetTrinityString(uint32 entry) const
{
return m_session->GetTrinityString(entry);
@@ -260,27 +249,6 @@ void ChatHandler::SendSysMessage(uint32 entry)
SendSysMessage(GetTrinityString(entry));
}
void ChatHandler::PSendSysMessage(uint32 entry, ...)
{
const char *format = GetTrinityString(entry);
va_list ap;
char str [2048];
va_start(ap, entry);
vsnprintf(str, 2048, format, ap);
va_end(ap);
SendSysMessage(str);
}
void ChatHandler::PSendSysMessage(const char *format, ...)
{
va_list ap;
char str [2048];
va_start(ap, format);
vsnprintf(str, 2048, format, ap);
va_end(ap);
SendSysMessage(str);
}
bool ChatHandler::ExecuteCommandInTable(ChatCommand* table, const char* text, std::string const& fullcmd)
{
char const* oldtext = text;

View File

@@ -20,6 +20,7 @@
#define TRINITYCORE_CHAT_H
#include "SharedDefines.h"
#include "StringFormat.h"
#include "WorldSession.h"
#include "RBAC.h"
#include "Packets/ChatPackets.h"
@@ -61,9 +62,24 @@ class ChatHandler
virtual void SendSysMessage(char const* str);
void SendSysMessage(uint32 entry);
void PSendSysMessage(char const* format, ...) ATTR_PRINTF(2, 3);
void PSendSysMessage(uint32 entry, ...);
std::string PGetParseString(uint32 entry, ...) const;
template<typename... Args>
void PSendSysMessage(const char* fmt, Args const&... args)
{
SendSysMessage(Trinity::StringFormat(fmt, args...).c_str());
}
template<typename... Args>
void PSendSysMessage(uint32 entry, Args const&... args)
{
SendSysMessage(PGetParseString(entry, args...).c_str());
}
template<typename... Args>
std::string PGetParseString(uint32 entry, Args const&... args) const
{
return Trinity::StringFormat(GetTrinityString(entry), args...);
}
bool ParseCommands(const char* text);

View File

@@ -3358,6 +3358,8 @@ void ObjectMgr::BuildPlayerLevelInfo(uint8 race, uint8 _class, uint8 level, Play
}
}
int32 const ReputationMgr::Reputation_Cap;
void ObjectMgr::LoadQuests()
{
uint32 oldMSTime = getMSTime();

View File

@@ -51,6 +51,8 @@ WorldSocketMgr::~WorldSocketMgr()
delete _instanceAcceptor;
}
int const boost::asio::socket_base::max_connections;
bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port)
{
_tcpNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true);

View File

@@ -51,6 +51,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/zlib
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration

View File

@@ -61,6 +61,7 @@ include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/utf8cpp
${CMAKE_SOURCE_DIR}/src/server
${CMAKE_CURRENT_SOURCE_DIR}

View File

@@ -18,6 +18,10 @@
#include "Appender.h"
#include "Common.h"
#include "Util.h"
#include "StringFormat.h"
#include <utility>
#include <sstream>
std::string LogMessage::getTimeStr(time_t time)
{
@@ -68,38 +72,36 @@ void Appender::setLogLevel(LogLevel _level)
level = _level;
}
void Appender::write(LogMessage& message)
void Appender::write(LogMessage* message)
{
if (!level || level > message.level)
if (!level || level > message->level)
return;
message.prefix.clear();
std::ostringstream ss;
if (flags & APPENDER_FLAGS_PREFIX_TIMESTAMP)
message.prefix.append(message.getTimeStr());
ss << message->getTimeStr();
if (flags & APPENDER_FLAGS_PREFIX_LOGLEVEL)
{
if (!message.prefix.empty())
message.prefix.push_back(' ');
if (ss.rdbuf()->in_avail() == 0)
ss << ' ';
char text[MAX_QUERY_LEN];
snprintf(text, MAX_QUERY_LEN, "%-5s", Appender::getLogLevelString(message.level));
message.prefix.append(text);
ss << Trinity::StringFormat("%-5s", Appender::getLogLevelString(message->level));
}
if (flags & APPENDER_FLAGS_PREFIX_LOGFILTERTYPE)
{
if (!message.prefix.empty())
message.prefix.push_back(' ');
if (ss.rdbuf()->in_avail() == 0)
ss << ' ';
message.prefix.push_back('[');
message.prefix.append(message.type);
message.prefix.push_back(']');
ss << '[' << message->type << ']';
}
if (!message.prefix.empty())
message.prefix.push_back(' ');
if (ss.rdbuf()->in_avail() == 0)
ss << ' ';
message->prefix = std::move(ss.str());
_write(message);
}

View File

@@ -21,6 +21,7 @@
#include <unordered_map>
#include <string>
#include <time.h>
#include <type_traits>
#include "Define.h"
// Values assigned have their equivalent in enum ACE_Log_Priority
@@ -57,16 +58,16 @@ enum AppenderFlags
struct LogMessage
{
LogMessage(LogLevel _level, std::string const& _type, std::string const& _text)
: level(_level), type(_type), text(_text), mtime(time(NULL))
LogMessage(LogLevel _level, std::string const& _type, std::string&& _text)
: level(_level), type(_type), text(std::forward<std::string>(_text)), mtime(time(NULL))
{ }
static std::string getTimeStr(time_t time);
std::string getTimeStr();
LogLevel level;
std::string type;
std::string text;
LogLevel const level;
std::string const type;
std::string const text;
std::string prefix;
std::string param1;
time_t mtime;
@@ -91,11 +92,11 @@ class Appender
AppenderFlags getFlags() const;
void setLogLevel(LogLevel);
void write(LogMessage& message);
void write(LogMessage* message);
static const char* getLogLevelString(LogLevel level);
private:
virtual void _write(LogMessage const& /*message*/) = 0;
virtual void _write(LogMessage const* /*message*/) = 0;
uint8 id;
std::string name;

View File

@@ -158,14 +158,14 @@ void AppenderConsole::ResetColor(bool stdout_stream)
#endif
}
void AppenderConsole::_write(LogMessage const& message)
void AppenderConsole::_write(LogMessage const* message)
{
bool stdout_stream = !(message.level == LOG_LEVEL_ERROR || message.level == LOG_LEVEL_FATAL);
bool stdout_stream = !(message->level == LOG_LEVEL_ERROR || message->level == LOG_LEVEL_FATAL);
if (_colored)
{
uint8 index;
switch (message.level)
switch (message->level)
{
case LOG_LEVEL_TRACE:
index = 5;
@@ -189,9 +189,9 @@ void AppenderConsole::_write(LogMessage const& message)
}
SetColor(stdout_stream, _colors[index]);
utf8printf(stdout_stream ? stdout : stderr, "%s%s", message.prefix.c_str(), message.text.c_str());
utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str());
ResetColor(stdout_stream);
}
else
utf8printf(stdout_stream ? stdout : stderr, "%s%s", message.prefix.c_str(), message.text.c_str());
utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str());
}

View File

@@ -51,7 +51,7 @@ class AppenderConsole: public Appender
private:
void SetColor(bool stdout_stream, ColorTypes color);
void ResetColor(bool stdout_stream);
void _write(LogMessage const& message) override;
void _write(LogMessage const* message) override;
bool _colored;
ColorTypes _colors[MaxLogLevels];
};

View File

@@ -23,18 +23,18 @@ AppenderDB::AppenderDB(uint8 id, std::string const& name, LogLevel level)
AppenderDB::~AppenderDB() { }
void AppenderDB::_write(LogMessage const& message)
void AppenderDB::_write(LogMessage const* message)
{
// Avoid infinite loop, PExecute triggers Logging with "sql.sql" type
if (!enabled || (message.type.find("sql") != std::string::npos))
if (!enabled || (message->type.find("sql") != std::string::npos))
return;
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_LOG);
stmt->setUInt64(0, message.mtime);
stmt->setUInt64(0, message->mtime);
stmt->setUInt32(1, realmId);
stmt->setString(2, message.type);
stmt->setUInt8(3, uint8(message.level));
stmt->setString(4, message.text);
stmt->setString(2, message->type);
stmt->setUInt8(3, uint8(message->level));
stmt->setString(4, message->text);
LoginDatabase.Execute(stmt);
}

View File

@@ -31,7 +31,7 @@ class AppenderDB: public Appender
private:
uint32 realmId;
bool enabled;
void _write(LogMessage const& message) override;
void _write(LogMessage const* message) override;
};
#endif

View File

@@ -43,21 +43,21 @@ AppenderFile::~AppenderFile()
CloseFile();
}
void AppenderFile::_write(LogMessage const& message)
void AppenderFile::_write(LogMessage const* message)
{
bool exceedMaxSize = maxFileSize > 0 && (fileSize.load() + message.Size()) > maxFileSize;
bool exceedMaxSize = maxFileSize > 0 && (fileSize.load() + message->Size()) > maxFileSize;
if (dynamicName)
{
char namebuf[TRINITY_PATH_MAX];
snprintf(namebuf, TRINITY_PATH_MAX, filename.c_str(), message.param1.c_str());
snprintf(namebuf, TRINITY_PATH_MAX, filename.c_str(), message->param1.c_str());
// always use "a" with dynamic name otherwise it could delete the log we wrote in last _write() call
FILE* file = OpenFile(namebuf, "a", backup || exceedMaxSize);
if (!file)
return;
fprintf(file, "%s%s", message.prefix.c_str(), message.text.c_str());
fprintf(file, "%s%s", message->prefix.c_str(), message->text.c_str());
fflush(file);
fileSize += uint64(message.Size());
fileSize += uint64(message->Size());
fclose(file);
return;
}
@@ -67,9 +67,9 @@ void AppenderFile::_write(LogMessage const& message)
if (!logfile)
return;
fprintf(logfile, "%s%s", message.prefix.c_str(), message.text.c_str());
fprintf(logfile, "%s%s\n", message->prefix.c_str(), message->text.c_str());
fflush(logfile);
fileSize += uint64(message.Size());
fileSize += uint64(message->Size());
}
FILE* AppenderFile::OpenFile(std::string const &filename, std::string const &mode, bool backup)

View File

@@ -30,7 +30,7 @@ class AppenderFile: public Appender
private:
void CloseFile();
void _write(LogMessage const& message) override;
void _write(LogMessage const* message) override;
FILE* logfile;
std::string filename;
std::string logDir;

View File

@@ -261,30 +261,18 @@ void Log::ReadLoggersFromConfig()
}
}
void Log::vlog(std::string const& filter, LogLevel level, char const* str, va_list argptr)
{
char text[MAX_QUERY_LEN];
vsnprintf(text, MAX_QUERY_LEN, str, argptr);
write(new LogMessage(level, filter, text));
}
void Log::write(LogMessage* msg) const
void Log::write(std::unique_ptr<LogMessage>&& msg) const
{
Logger const* logger = GetLoggerByType(msg->type);
msg->text.append("\n");
if (_ioService)
{
auto logOperation = std::shared_ptr<LogOperation>(new LogOperation(logger, msg));
auto logOperation = std::shared_ptr<LogOperation>(new LogOperation(logger, std::forward<std::unique_ptr<LogMessage>>(msg)));
_ioService->post(_strand->wrap([logOperation](){ logOperation->call(); }));
}
else
{
logger->write(*msg);
delete msg;
}
logger->write(msg.get());
}
std::string Log::GetTimestampStr()
@@ -343,33 +331,13 @@ void Log::outCharDump(char const* str, uint32 accountId, uint64 guid, char const
ss << "== START DUMP == (account: " << accountId << " guid: " << guid << " name: " << name
<< ")\n" << str << "\n== END DUMP ==\n";
LogMessage* msg = new LogMessage(LOG_LEVEL_INFO, "entities.player.dump", ss.str());
std::unique_ptr<LogMessage> msg(new LogMessage(LOG_LEVEL_INFO, "entities.player.dump", ss.str()));
std::ostringstream param;
param << guid << '_' << name;
msg->param1 = param.str();
write(msg);
}
void Log::outCommand(uint32 account, const char * str, ...)
{
if (!str || !ShouldLog("commands.gm", LOG_LEVEL_INFO))
return;
va_list ap;
va_start(ap, str);
char text[MAX_QUERY_LEN];
vsnprintf(text, MAX_QUERY_LEN, str, ap);
va_end(ap);
LogMessage* msg = new LogMessage(LOG_LEVEL_INFO, "commands.gm", text);
std::ostringstream ss;
ss << account;
msg->param1 = ss.str();
write(msg);
write(std::move(msg));
}
void Log::SetRealmId(uint32 id)

View File

@@ -22,12 +22,13 @@
#include "Define.h"
#include "Appender.h"
#include "Logger.h"
#include <stdarg.h>
#include "StringFormat.h"
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
#include <unordered_map>
#include <string>
#include <memory>
#define LOGGER_ROOT "root"
@@ -59,17 +60,34 @@ class Log
bool ShouldLog(std::string const& type, LogLevel level) const;
bool SetLogLevel(std::string const& name, char const* level, bool isLogger = true);
void outMessage(std::string const& f, LogLevel level, char const* str, ...) ATTR_PRINTF(4, 5);
template<typename... Args>
inline void outMessage(std::string const& filter, LogLevel const level, const char* fmt, Args const&... args)
{
write(std::move(std::unique_ptr<LogMessage>(new LogMessage(level, filter, std::move(Trinity::StringFormat(fmt, args...))))));
}
template<typename... Args>
void outCommand(uint32 account, const char* fmt, Args const&... args)
{
if (!ShouldLog("commands.gm", LOG_LEVEL_INFO))
return;
std::unique_ptr<LogMessage> msg(new LogMessage(LOG_LEVEL_INFO, "commands.gm", std::move(Trinity::StringFormat(fmt, args...))));
std::ostringstream ss;
ss << account;
msg->param1 = ss.str();
write(std::move(msg));
}
void outCommand(uint32 account, const char * str, ...) ATTR_PRINTF(3, 4);
void outCharDump(char const* str, uint32 account_id, uint64 guid, char const* name);
void SetRealmId(uint32 id);
private:
static std::string GetTimestampStr();
void vlog(std::string const& f, LogLevel level, char const* str, va_list argptr);
void write(LogMessage* msg) const;
void write(std::unique_ptr<LogMessage>&& msg) const;
Logger const* GetLoggerByType(std::string const& type) const;
Appender* GetAppenderByName(std::string const& name);
@@ -121,23 +139,34 @@ inline bool Log::ShouldLog(std::string const& type, LogLevel level) const
return logLevel != LOG_LEVEL_DISABLED && logLevel <= level;
}
inline void Log::outMessage(std::string const& filter, LogLevel level, const char * str, ...)
{
va_list ap;
va_start(ap, str);
vlog(filter, level, str, ap);
va_end(ap);
}
#define sLog Log::instance()
#define LOG_EXCEPTION_FREE(filterType__, level__, ...) \
{ \
try \
{ \
sLog->outMessage(filterType__, level__, __VA_ARGS__); \
} \
catch (std::exception& e) \
{ \
sLog->outMessage("server", LOG_LEVEL_ERROR, "Wrong format occurred (%s) at %s:%u.", \
e.what(), __FILE__, __LINE__); \
} \
}
#if PLATFORM != PLATFORM_WINDOWS
void check_args(const char* format, ...) ATTR_PRINTF(1, 2);
// This will catch format errors on build time
#define TC_LOG_MESSAGE_BODY(filterType__, level__, ...) \
do { \
if (sLog->ShouldLog(filterType__, level__)) \
sLog->outMessage(filterType__, level__, __VA_ARGS__); \
{ \
if (false) \
check_args(__VA_ARGS__); \
\
LOG_EXCEPTION_FREE(filterType__, level__, __VA_ARGS__); \
} \
} while (0)
#else
#define TC_LOG_MESSAGE_BODY(filterType__, level__, ...) \
@@ -145,7 +174,7 @@ inline void Log::outMessage(std::string const& filter, LogLevel level, const cha
__pragma(warning(disable:4127)) \
do { \
if (sLog->ShouldLog(filterType__, level__)) \
sLog->outMessage(filterType__, level__, __VA_ARGS__); \
LOG_EXCEPTION_FREE(filterType__, level__, __VA_ARGS__); \
} while (0) \
__pragma(warning(pop))
#endif

View File

@@ -18,14 +18,8 @@
#include "LogOperation.h"
#include "Logger.h"
LogOperation::~LogOperation()
{
delete msg;
}
int LogOperation::call()
{
if (logger && msg)
logger->write(*msg);
logger->write(msg.get());
return 0;
}

View File

@@ -18,23 +18,25 @@
#ifndef LOGOPERATION_H
#define LOGOPERATION_H
#include <memory>
class Logger;
struct LogMessage;
class LogOperation
{
public:
LogOperation(Logger const* _logger, LogMessage* _msg)
: logger(_logger), msg(_msg)
LogOperation(Logger const* _logger, std::unique_ptr<LogMessage>&& _msg)
: logger(_logger), msg(std::forward<std::unique_ptr<LogMessage>>(_msg))
{ }
~LogOperation();
~LogOperation() { }
int call();
protected:
Logger const* logger;
LogMessage* msg;
std::unique_ptr<LogMessage> msg;
};
#endif

View File

@@ -50,9 +50,9 @@ void Logger::setLogLevel(LogLevel _level)
level = _level;
}
void Logger::write(LogMessage& message) const
void Logger::write(LogMessage* message) const
{
if (!level || level > message.level || message.text.empty())
if (!level || level > message->level || message->text.empty())
{
//fprintf(stderr, "Logger::write: Logger %s, Level %u. Msg %s Level %u WRONG LEVEL MASK OR EMPTY MSG\n", getName().c_str(), getLogLevel(), message.text.c_str(), message.level);
return;

View File

@@ -32,7 +32,7 @@ class Logger
std::string const& getName() const;
LogLevel getLogLevel() const;
void setLogLevel(LogLevel level);
void write(LogMessage& message) const;
void write(LogMessage* message) const;
private:
std::string name;

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRINITYCORE_STRING_FORMAT_H
#define TRINITYCORE_STRING_FORMAT_H
#include <format.h>
namespace Trinity
{
//! Default TC string format function
template<typename... Args>
inline std::string StringFormat(const char* fmt, Args const&... args)
{
return fmt::sprintf(fmt, args...);
}
}
#endif

View File

@@ -47,6 +47,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/dep/gsoap
${CMAKE_SOURCE_DIR}/dep/sockets/include
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/zmqpp
${CMAKE_SOURCE_DIR}/src/server/collision
${CMAKE_SOURCE_DIR}/src/server/collision/Management
@@ -175,6 +176,7 @@ target_link_libraries(worldserver
gsoap
Detour
zmqpp
format
${JEMALLOC_LIBRARY}
${READLINE_LIBRARY}
${TERMCAP_LIBRARY}