summaryrefslogtreecommitdiff
path: root/src/utils/log.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/log.cpp')
-rw-r--r--src/utils/log.cpp165
1 files changed, 165 insertions, 0 deletions
diff --git a/src/utils/log.cpp b/src/utils/log.cpp
new file mode 100644
index 0000000..d26f053
--- /dev/null
+++ b/src/utils/log.cpp
@@ -0,0 +1,165 @@
+//------------------------------------------------------------------------------
+// Author: Pavel Karneliuk
+// Description: Reentrant logger implementation
+// Copyright (c) 2013 EPAM Systems
+//------------------------------------------------------------------------------
+/*
+ This file is part of Nfstrace.
+
+ Nfstrace 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, version 2 of the License.
+
+ Nfstrace 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 Nfstrace. If not, see <http://www.gnu.org/licenses/>.
+*/
+//------------------------------------------------------------------------------
+#include <cstdarg>
+#include <cstdio>
+#include <cerrno>
+#include <iostream>
+#include <stdexcept>
+#include <system_error>
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "utils/log.h"
+#include "utils/out.h"
+//------------------------------------------------------------------------------
+/* http://www.unix.org/whitepapers/reentrant.html
+ The POSIX.1 and C-language functions that operate on character streams
+ (represented by pointers to objects of type FILE) are required by POSIX.1c
+ to be implemented in such a way that reentrancy is achieved
+ (see ISO/IEC 9945:1-1996, ยง8.2). This requirement has a drawback; it imposes
+ substantial performance penalties because of the synchronization that must
+ be built into the implementations of the functions for the sake of reentrancy.
+*/
+//------------------------------------------------------------------------------
+namespace NST
+{
+namespace utils
+{
+
+static FILE* log_file {::stderr};
+static bool own_file {false};
+
+namespace // unnanmed
+{
+
+static std::string get_pid()
+{
+ char buff[8]={'\0'};
+ sprintf(buff,"%ld",(long)getpid());
+ return std::string{buff};
+}
+
+static FILE* try_open(const std::string& file_name)
+{
+ FILE* file {fopen(file_name.c_str(), "w")};
+ if(file == nullptr)
+ {
+ throw std::system_error{errno, std::system_category(),
+ "Error in opening file."};
+ }
+ chmod(file_name.c_str(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ if(flock(fileno(file), LOCK_EX | LOCK_NB))
+ {
+ fclose(file);
+ throw std::system_error{errno, std::system_category(),
+ "Log file already locked"};
+ }
+ return file;
+}
+
+} // namespace unnamed
+
+Log::Global::Global(const std::string& path)
+{
+ const std::string log_path{"/tmp/nfstrace"};
+
+ if(log_file != ::stderr)
+ {
+ throw std::runtime_error{"Global Logger already have been created"};
+ }
+
+ if(path.empty()) return;
+
+ struct stat s;
+ if(stat(log_path.c_str(), &s)) // check destination folder exists
+ {
+ if(mkdir(log_path.c_str(), ALLPERMS)) // create directory for nfs logs
+ {
+ throw std::system_error{errno, std::system_category(),
+ "Can't create log directory."};
+ }
+ }
+ std::string tmp{log_path + '/' + path + ".log"};
+ FILE* file {nullptr};
+ try
+ {
+ file = try_open(tmp);
+ }
+ catch(std::system_error& err)
+ {
+ tmp = log_path + '/' + path + '-' + get_pid() + ".log";
+ file = try_open(tmp);
+ }
+ if(utils::Out message{})
+ {
+ message << "Log folder: " << log_path;
+ }
+
+ log_file = file;
+ own_file = true;
+}
+
+Log::Global::~Global()
+{
+ if(own_file)
+ {
+ flock(fileno(log_file), LOCK_UN);
+ fclose(log_file);
+ own_file = false;
+ log_file = ::stderr;
+ }
+}
+
+Log::Log()
+: std::stringbuf {ios_base::out}
+, std::ostream {nullptr}
+{
+ std::stringbuf::setp(buffer, buffer+sizeof(buffer));
+ std::ostream::init(static_cast<std::stringbuf*>(this));
+ std::ostream::put('\n');
+}
+
+Log::~Log()
+{
+ size_t len = pptr() - pbase();
+ fwrite(pbase(), len, 1, log_file);
+}
+
+void Log::message(const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(log_file, format, args);
+ va_end(args);
+}
+
+void Log::flush()
+{
+ fflush(log_file);
+}
+
+} // namespace utils
+} // namespace NST
+//------------------------------------------------------------------------------