summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
authorJose <jose@zeroc.com>2016-04-07 10:29:11 +0200
committerJose <jose@zeroc.com>2016-04-07 10:29:11 +0200
commit058a0c6c3ee2f059be0d8c7eba940aa31463fa7f (patch)
treea52b7eb37253b8da13db2b7f617f3233b440bbfb /cpp
parentFixed issue with IE where accessing the stack from Exception.toString leads t... (diff)
downloadice-058a0c6c3ee2f059be0d8c7eba940aa31463fa7f.tar.bz2
ice-058a0c6c3ee2f059be0d8c7eba940aa31463fa7f.tar.xz
ice-058a0c6c3ee2f059be0d8c7eba940aa31463fa7f.zip
ICE-7035 - Add option to roll log files
Diffstat (limited to 'cpp')
-rw-r--r--cpp/include/IceUtil/Time.h5
-rw-r--r--cpp/src/Ice/Instance.cpp4
-rw-r--r--cpp/src/Ice/LoggerI.cpp72
-rw-r--r--cpp/src/Ice/LoggerI.h4
-rw-r--r--cpp/src/Ice/PropertyNames.cpp3
-rw-r--r--cpp/src/Ice/PropertyNames.h2
-rw-r--r--cpp/src/IceUtil/Time.cpp38
-rw-r--r--cpp/test/Ice/logger/.gitignore1
-rw-r--r--cpp/test/Ice/logger/Client5.cpp138
-rw-r--r--cpp/test/Ice/logger/Makefile11
-rw-r--r--cpp/test/Ice/logger/Makefile.mak13
-rwxr-xr-xcpp/test/Ice/logger/run.py63
12 files changed, 322 insertions, 32 deletions
diff --git a/cpp/include/IceUtil/Time.h b/cpp/include/IceUtil/Time.h
index abfc48c7854..9b29a862391 100644
--- a/cpp/include/IceUtil/Time.h
+++ b/cpp/include/IceUtil/Time.h
@@ -28,7 +28,7 @@ public:
// No copy constructor and assignment operator necessary. The
// automatically generated copy constructor and assignment
// operator do the right thing.
-
+
enum Clock { Realtime, Monotonic };
static Time now(Clock = Realtime);
@@ -39,7 +39,7 @@ public:
static Time secondsDouble(double);
static Time milliSecondsDouble(double);
static Time microSecondsDouble(double);
-
+
#ifndef _WIN32
operator timeval() const;
#endif
@@ -54,6 +54,7 @@ public:
std::string toDateTime() const;
std::string toDuration() const;
+ std::string toFormatString(const std::string&) const;
Time operator-() const
{
diff --git a/cpp/src/Ice/Instance.cpp b/cpp/src/Ice/Instance.cpp
index 75912ec0c10..c08a021c02f 100644
--- a/cpp/src/Ice/Instance.cpp
+++ b/cpp/src/Ice/Instance.cpp
@@ -1230,7 +1230,9 @@ IceInternal::Instance::Instance(const CommunicatorPtr& communicator, const Initi
#endif
if(!logfile.empty())
{
- _initData.logger = new LoggerI(_initData.properties->getProperty("Ice.ProgramName"), logfile);
+ _initData.logger =
+ new LoggerI(_initData.properties->getProperty("Ice.ProgramName"), logfile, true, 0,
+ _initData.properties->getPropertyAsIntWithDefault("Ice.LogFile.SizeMax", 0));
}
else
{
diff --git a/cpp/src/Ice/LoggerI.cpp b/cpp/src/Ice/LoggerI.cpp
index 623ed3403ff..41809daf7b1 100644
--- a/cpp/src/Ice/LoggerI.cpp
+++ b/cpp/src/Ice/LoggerI.cpp
@@ -9,11 +9,11 @@
#include <IceUtil/Time.h>
#include <Ice/LoggerI.h>
+#include <IceUtil/StringUtil.h>
#include <IceUtil/Mutex.h>
#include <IceUtil/MutexPtrLock.h>
#ifdef _WIN32
-# include <IceUtil/StringUtil.h>
# include <IceUtil/ScopedArray.h>
#endif
@@ -49,14 +49,15 @@ Init init;
}
Ice::LoggerI::LoggerI(const string& prefix, const string& file,
- bool convert, const IceUtil::StringConverterPtr& converter) :
+ bool convert, const IceUtil::StringConverterPtr& converter,
+ size_t sizeMax) :
_prefix(prefix),
_convert(convert),
- _converter(converter)
+ _converter(converter),
#if defined(_WIN32) && !defined(ICE_OS_WINRT)
- , _consoleConverter(new IceUtil::WindowsStringConverter(GetConsoleOutputCP()))
+ _consoleConverter(new IceUtil::WindowsStringConverter(GetConsoleOutputCP())),
#endif
-
+ _sizeMax(sizeMax)
{
if(!prefix.empty())
{
@@ -144,6 +145,67 @@ Ice::LoggerI::write(const string& message, bool indent)
if(_out.is_open())
{
+ if(_sizeMax > 0)
+ {
+ _out.seekp(0, _out.end);
+
+ //
+ // If file size + message size exceed max size we archive the log file,
+ // but we do not archive empty files or truncate messages.
+ //
+ size_t sz = static_cast<size_t>(_out.tellp());
+ if(sz > 0 && sz + message.size() >= _sizeMax)
+ {
+
+ string basename = _file;
+ string ext;
+
+ size_t i = basename.rfind(".");
+ if(i != string::npos && i + 1 < basename.size())
+ {
+ ext = basename.substr(i + 1);
+ basename = basename.substr(0, i);
+ }
+ _out.close();
+
+ int id = 0;
+ string archive;
+ string date = IceUtil::Time::now().toFormatString("%Y%m%d-%H%M%S");
+ while(true)
+ {
+ ostringstream s;
+ s << basename << "-" << date;
+ if(id > 0)
+ {
+ s << "-" << id;
+ }
+ if(!ext.empty())
+ {
+ s << "." << ext;
+ }
+ if(IceUtilInternal::fileExists(s.str()))
+ {
+ id++;
+ continue;
+ }
+ archive = s.str();
+ break;
+ }
+
+ int error = IceUtilInternal::rename(_file, archive);
+ if(error)
+ {
+ throw InitializationException(__FILE__, __LINE__, "FileLogger: cannot rename " + _file + "\n" +
+ IceUtilInternal::lastErrorToString());
+ }
+
+ _out.open(_file, fstream::out | fstream::app);
+ if(!_out.is_open())
+ {
+ throw InitializationException(__FILE__, __LINE__, "FileLogger: cannot open " + _file);
+ }
+ }
+ }
_out << s << endl;
}
else
diff --git a/cpp/src/Ice/LoggerI.h b/cpp/src/Ice/LoggerI.h
index 4ff54d73b41..fbfb35b5a63 100644
--- a/cpp/src/Ice/LoggerI.h
+++ b/cpp/src/Ice/LoggerI.h
@@ -22,7 +22,7 @@ class LoggerI : public Logger
public:
LoggerI(const std::string&, const std::string&, bool convert = true,
- const IceUtil::StringConverterPtr& converter = 0);
+ const IceUtil::StringConverterPtr& converter = 0, std::size_t sizeMax = 0);
~LoggerI();
virtual void print(const std::string&);
@@ -43,7 +43,7 @@ private:
IceUtilInternal::ofstream _out;
std::string _file;
-
+ std::size_t _sizeMax;
#if defined(_WIN32) && !defined(ICE_OS_WINRT)
const IceUtil::StringConverterPtr _consoleConverter;
#endif
diff --git a/cpp/src/Ice/PropertyNames.cpp b/cpp/src/Ice/PropertyNames.cpp
index 9ce120d99b8..69f03cade5f 100644
--- a/cpp/src/Ice/PropertyNames.cpp
+++ b/cpp/src/Ice/PropertyNames.cpp
@@ -6,7 +6,7 @@
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************
-// Generated by makeprops.py from file ./config/PropertyNames.xml, Tue Apr 28 22:03:41 2015
+// Generated by makeprops.py from file ./config/PropertyNames.xml, Thu Apr 7 10:23:17 2016
// IMPORTANT: Do not edit this file -- any edits made here will be lost!
@@ -123,6 +123,7 @@ const IceInternal::Property IcePropsData[] =
IceInternal::Property("Ice.IPv4", false, 0),
IceInternal::Property("Ice.IPv6", false, 0),
IceInternal::Property("Ice.LogFile", false, 0),
+ IceInternal::Property("Ice.LogFile.SizeMax", false, 0),
IceInternal::Property("Ice.LogStdErr.Convert", false, 0),
IceInternal::Property("Ice.MessageSizeMax", false, 0),
IceInternal::Property("Ice.Nohup", false, 0),
diff --git a/cpp/src/Ice/PropertyNames.h b/cpp/src/Ice/PropertyNames.h
index c0d5538e51e..d5712c8e2ab 100644
--- a/cpp/src/Ice/PropertyNames.h
+++ b/cpp/src/Ice/PropertyNames.h
@@ -6,7 +6,7 @@
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************
-// Generated by makeprops.py from file ./config/PropertyNames.xml, Tue Apr 28 22:03:41 2015
+// Generated by makeprops.py from file ./config/PropertyNames.xml, Thu Apr 7 10:23:17 2016
// IMPORTANT: Do not edit this file -- any edits made here will be lost!
diff --git a/cpp/src/IceUtil/Time.cpp b/cpp/src/IceUtil/Time.cpp
index d792757a9f1..aa6f6e944d9 100644
--- a/cpp/src/IceUtil/Time.cpp
+++ b/cpp/src/IceUtil/Time.cpp
@@ -247,22 +247,8 @@ IceUtil::Time::toMicroSecondsDouble() const
std::string
IceUtil::Time::toDateTime() const
{
- time_t time = static_cast<long>(_usec / 1000000);
-
- struct tm* t;
-#ifdef _WIN32
- t = localtime(&time);
-#else
- struct tm tr;
- localtime_r(&time, &tr);
- t = &tr;
-#endif
-
- char buf[32];
- strftime(buf, sizeof(buf), "%x %H:%M:%S", t);
-
std::ostringstream os;
- os << buf << ".";
+ os << toFormatString("%x %H:%M:%S") << ".";
os.fill('0');
os.width(3);
os << static_cast<long>(_usec % 1000000 / 1000);
@@ -294,6 +280,28 @@ IceUtil::Time::toDuration() const
return os.str();
}
+std::string
+IceUtil::Time::toFormatString(const std::string& format) const
+{
+ time_t time = static_cast<long>(_usec / 1000000);
+
+ struct tm* t;
+#ifdef _WIN32
+ t = localtime(&time);
+#else
+ struct tm tr;
+ localtime_r(&time, &tr);
+ t = &tr;
+#endif
+
+ char buf[32];
+ if(strftime(buf, sizeof(buf), format.c_str(), t) == 0)
+ {
+ return std::string();
+ }
+ return std::string(buf);
+}
+
Time::Time(Int64 usec) :
_usec(usec)
{
diff --git a/cpp/test/Ice/logger/.gitignore b/cpp/test/Ice/logger/.gitignore
index a918a882f43..b92e9bec8ae 100644
--- a/cpp/test/Ice/logger/.gitignore
+++ b/cpp/test/Ice/logger/.gitignore
@@ -6,4 +6,5 @@ client1
client2
client3
client4
+client5
.depend
diff --git a/cpp/test/Ice/logger/Client5.cpp b/cpp/test/Ice/logger/Client5.cpp
new file mode 100644
index 00000000000..5948e2eed9c
--- /dev/null
+++ b/cpp/test/Ice/logger/Client5.cpp
@@ -0,0 +1,138 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <Ice/Ice.h>
+#include <TestCommon.h>
+
+using namespace std;
+
+namespace
+{
+
+class Client : public Ice::Application
+{
+public:
+ virtual int
+ run(int, char*[])
+ {
+ int count = communicator()->getProperties()->getPropertyAsInt("Client.Iterations");
+ const string message = communicator()->getProperties()->getProperty("Client.Message");
+ for(int i = 0; i < count; ++i)
+ {
+ communicator()->getLogger()->print(message);
+ }
+ return EXIT_SUCCESS;
+ };
+};
+
+}
+
+//
+// We use messages with different sizes to compensate the different line end used in Windows
+// and Unix. The Win32 message is 126 bytes plus 2 bytes for the Windows line end \r\n and
+// that makes a total of 128 bytes. For all other platforms the message is 127 bytes plus 1
+// byte for the line end \n and that makes a total of 128 bytes.
+//
+#ifdef _WIN32
+const string message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
+ "Vestibulum ornare, ex non bibendum hendrerit, felis tortor cras amet.";
+#else
+const string message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
+ "Fusce dictum turpis ante, sit amet finibus eros commodo vel. Sed amet.";
+#endif
+
+int
+main(int argc, char* argv[])
+{
+#ifdef ICE_STATIC_LIBS
+ Ice::registerIceSSL();
+#endif
+
+ //
+ // Run Client application 20 times, each times it generate 512 bytes of log messages,
+ // the application logger is configured to archive log files larger than 512 bytes.
+ //
+ // This will generate 19 archived log files, all files including current log file
+ // must have 512 bytes length.
+ //
+ for(int i = 0; i < 20; ++i)
+ {
+ Ice::InitializationData id;
+ id.properties = Ice::createProperties();
+ id.properties->load("config.client");
+ id.properties->setProperty("Client.Iterations", "4");
+ id.properties->setProperty("Client.Message", message);
+ id.properties->setProperty("Ice.LogFile", "client5-0.log");
+ id.properties->setProperty("Ice.LogFile.SizeMax", "512");
+ Client c;
+ if(c.main(argc, argv, id) != EXIT_SUCCESS)
+ {
+ return EXIT_FAILURE;
+ }
+ }
+
+ //
+ // Run Client application configured to generate 1024 bytes, the application is configured
+ // to not archive log files, there must not be any archived log files, and log file must
+ // have 1024 bytes size.
+ //
+ {
+ Ice::InitializationData id;
+ id.properties = Ice::createProperties();
+ id.properties->load("config.client");
+ id.properties->setProperty("Client.Iterations", "8");
+ id.properties->setProperty("Client.Message", message);
+ id.properties->setProperty("Ice.LogFile", "client5-1.log");
+ id.properties->setProperty("Ice.LogFile.SizeMax", "0");
+ Client c;
+ if(c.main(argc, argv, id) != EXIT_SUCCESS)
+ {
+ return EXIT_FAILURE;
+ }
+ }
+
+ //
+ // Run Client application configured to generate 1024 bytes, the application is configured
+ // to archive log files when size is greatert than 128 bytes, there should be 7 archived files
+ // and current log file, all files must have 128 bytes size.
+ //
+ {
+ Ice::InitializationData id;
+ id.properties = Ice::createProperties();
+ id.properties->load("config.client");
+ id.properties->setProperty("Client.Iterations", "8");
+ id.properties->setProperty("Client.Message", message);
+ id.properties->setProperty("Ice.LogFile", "client5-2.log");
+ id.properties->setProperty("Ice.LogFile.SizeMax", "128");
+ Client c;
+ if(c.main(argc, argv, id) != EXIT_SUCCESS)
+ {
+ return EXIT_FAILURE;
+ }
+ }
+
+ //
+ // Same as above but maximum size is lower than the message size, in this case we should
+ // get the same result as messages are not trucated.
+ //
+ {
+ Ice::InitializationData id;
+ id.properties = Ice::createProperties();
+ id.properties->load("config.client");
+ id.properties->setProperty("Client.Iterations", "8");
+ id.properties->setProperty("Client.Message", message);
+ id.properties->setProperty("Ice.LogFile", "client5-3.log");
+ id.properties->setProperty("Ice.LogFile.SizeMax", "64");
+ Client c;
+ if(c.main(argc, argv, id) != EXIT_SUCCESS)
+ {
+ return EXIT_FAILURE;
+ }
+ }
+}
diff --git a/cpp/test/Ice/logger/Makefile b/cpp/test/Ice/logger/Makefile
index 4ac48f3c39c..48c270503ad 100644
--- a/cpp/test/Ice/logger/Makefile
+++ b/cpp/test/Ice/logger/Makefile
@@ -13,18 +13,21 @@ CLIENT1 = $(call mktestname,client1)
CLIENT2 = $(call mktestname,client2)
CLIENT3 = $(call mktestname,client3)
CLIENT4 = $(call mktestname,client4)
+CLIENT5 = $(call mktestname,client5)
-TARGETS = $(CLIENT1) $(CLIENT2) $(CLIENT3) $(CLIENT4)
+TARGETS = $(CLIENT1) $(CLIENT2) $(CLIENT3) $(CLIENT4) $(CLIENT5)
C1OBJS = Client1.o
C2OBJS = Client2.o
C3OBJS = Client3.o
C4OBJS = Client4.o
+C5OBJS = Client5.o
OBJS = $(C1OBJS) \
$(C2OBJS) \
$(C3OBJS) \
- $(C4OBJS)
+ $(C4OBJS) \
+ $(C5OBJS)
include $(top_srcdir)/config/Make.rules
@@ -47,3 +50,7 @@ $(CLIENT3): $(C3OBJS)
$(CLIENT4): $(C4OBJS)
rm -f $@
$(call mktest,$@,$(C4OBJS),$(LINKWITH))
+
+$(CLIENT5): $(C5OBJS)
+ rm -f $@
+ $(call mktest,$@,$(C5OBJS),$(LINKWITH))
diff --git a/cpp/test/Ice/logger/Makefile.mak b/cpp/test/Ice/logger/Makefile.mak
index 9fd96d5f8e6..131b68210ac 100644
--- a/cpp/test/Ice/logger/Makefile.mak
+++ b/cpp/test/Ice/logger/Makefile.mak
@@ -13,18 +13,21 @@ CLIENT1 = client1.exe
CLIENT2 = client2.exe
CLIENT3 = client3.exe
CLIENT4 = client4.exe
+CLIENT5 = client5.exe
-TARGETS = $(CLIENT1) $(CLIENT2) $(CLIENT3) $(CLIENT4)
+TARGETS = $(CLIENT1) $(CLIENT2) $(CLIENT3) $(CLIENT4) $(CLIENT5)
C1OBJS = .\Client1.obj
C2OBJS = .\Client2.obj
C3OBJS = .\Client3.obj
C4OBJS = .\Client4.obj
+C5OBJS = .\Client5.obj
OBJS = $(C1OBJS) \
$(C2OBJS) \
$(C3OBJS) \
- $(C4OBJS)
+ $(C4OBJS) \
+ $(C5OBJS)
!include $(top_srcdir)/config/Make.rules.mak
@@ -35,6 +38,7 @@ C1PDBFLAGS = /pdb:$(CLIENT1:.exe=.pdb)
C2PDBFLAGS = /pdb:$(CLIENT2:.exe=.pdb)
C3PDBFLAGS = /pdb:$(CLIENT3:.exe=.pdb)
C4PDBFLAGS = /pdb:$(CLIENT4:.exe=.pdb)
+C5PDBFLAGS = /pdb:$(CLIENT5:.exe=.pdb)
!endif
$(CLIENT1): $(C1OBJS)
@@ -56,3 +60,8 @@ $(CLIENT4): $(C4OBJS)
$(LINK) $(LD_EXEFLAGS) $(C4PDBFLAGS) $(SETARGV) $(C4OBJS) $(PREOUT)$@ $(PRELIBS)$(LIBS)
@if exist $@.manifest echo ^ ^ ^ Embedding manifest using $(MT) && \
$(MT) -nologo -manifest $@.manifest -outputresource:$@;#1 && del /q $@.manifest
+
+$(CLIENT5): $(C5OBJS)
+ $(LINK) $(LD_EXEFLAGS) $(C5PDBFLAGS) $(SETARGV) $(C5OBJS) $(PREOUT)$@ $(PRELIBS)$(LIBS)
+ @if exist $@.manifest echo ^ ^ ^ Embedding manifest using $(MT) && \
+ $(MT) -nologo -manifest $@.manifest -outputresource:$@;#1 && del /q $@.manifest
diff --git a/cpp/test/Ice/logger/run.py b/cpp/test/Ice/logger/run.py
index 2665663ca2b..1b645a5a5d2 100755
--- a/cpp/test/Ice/logger/run.py
+++ b/cpp/test/Ice/logger/run.py
@@ -9,7 +9,7 @@
#
# **********************************************************************
-import os, sys, subprocess
+import os, sys, subprocess, glob, atexit
path = [ ".", "..", "../..", "../../..", "../../../..", "../../../../.." ]
head = os.path.dirname(sys.argv[0])
@@ -52,3 +52,64 @@ if TestUtil.isWin32():
else:
test(os.path.join(os.getcwd(), "client4"), b'aplicaci\xf3n', "ISO-8859-15")
print("ok")
+
+sys.stdout.write("testing logger file rotation... ")
+
+def cleanup():
+ for f in glob.glob("client5-*.log"):
+ os.remove(f)
+
+cleanup()
+
+atexit.register(cleanup)
+
+def client5():
+ p = subprocess.Popen(os.path.join(os.getcwd(), "client5"), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env)
+ out, err = p.communicate()
+ ret = p.poll()
+ if ret != 0:
+ print("failed! status %s " % ret)
+ sys.exit(1)
+
+client5()
+
+if (not os.path.isfile("client5-0.log") or
+ not os.stat("client5-0.log").st_size == 512 or
+ len(glob.glob("client5-0-*.log")) != 19):
+ print("failed!")
+ sys.exit(1)
+
+for f in glob.glob("client5-0-*.log"):
+ if not os.stat(f).st_size == 512:
+ print("failed! file {0} size: {1} unexpected".format(f, os.stat(f).st_size))
+ sys.exit(1)
+
+if (not os.path.isfile("client5-1.log") or
+ not os.stat("client5-1.log").st_size == 1024 or
+ len(glob.glob("client5-1-*.log")) != 0):
+ print("failed!")
+ sys.exit(1)
+
+if (not os.path.isfile("client5-2.log") or
+ not os.stat("client5-2.log").st_size == 128 or
+ len(glob.glob("client5-2-*.log")) != 7):
+ print("failed!")
+ sys.exit(1)
+
+for f in glob.glob("client5-2-*.log"):
+ if not os.stat(f).st_size == 128:
+ print("failed! file {0} size: {1} unexpected".format(f, os.stat(f).st_size))
+ sys.exit(1)
+
+if (not os.path.isfile("client5-3.log") or
+ not os.stat("client5-2.log").st_size == 128 or
+ len(glob.glob("client5-2-*.log")) != 7):
+ print("failed!")
+ sys.exit(1)
+
+for f in glob.glob("client5-3-*.log"):
+ if not os.stat(f).st_size == 128:
+ print("failed! file {0} size: {1} unexpected".format(f, os.stat(f).st_size))
+ sys.exit(1)
+
+print("ok")