Merge branch 'master' into documentation-updates
diff --git a/.github/workflows/log4cxx.yml b/.github/workflows/log4cxx.yml
index d7b821e..ac725c0 100644
--- a/.github/workflows/log4cxx.yml
+++ b/.github/workflows/log4cxx.yml
@@ -45,11 +45,8 @@
 
     steps:
     - uses: actions/checkout@v2
-
-    - uses: lukka/set-shell-env@v1.1
       with:
-        CXX: ${{ matrix.cxx }}
-        CC: ${{ matrix.cc }}
+        path: main
 
     - name: 'Configure Dependencies - Ubuntu'
       if: matrix.name == 'ubuntu18-gcc' || matrix.name == 'ubuntu18-clang'
@@ -64,29 +61,49 @@
       if: matrix.name == 'windows-2019' || matrix.name == 'windows-2016'
       uses: actions/cache@v2
       with:
-        path: ${{ runner.workspace }}/vcpkg
+        path: vcpkg
         key: ${{ runner.os }}-${{ matrix.name }}-cache
 
-    - name: 'Configure Dependencies - Windows'
-      if: matrix.name == 'windows-2019' || matrix.name == 'windows-2016'
-      uses: lukka/run-vcpkg@v5
-      id: runvcpkg
+    - name: 'Checkout VCPKG - Windows'
+      if: (matrix.name == 'windows-2019' || matrix.name == 'windows-2016') && steps.restore-vcpkg-cache.outputs.cache-hit != 'true'
+      uses: actions/checkout@v2
       with:
-        vcpkgArguments: apr apr-util
-        vcpkgDirectory: ${{ runner.workspace }}/vcpkg/
-        vcpkgGitCommitId: ffa7fd27cfa29f206d1fd2ccfc722cad4aaeef3d
-        vcpkgTriplet: x64-windows
+        repository: microsoft/vcpkg
+        path: vcpkg
+        ref: ec6fe06e8da05a8157dc8581fa96b36b571c1bd5
 
-    - name: 'run cmake'
-      uses: lukka/run-cmake@v3
-      with:
-        cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
-        buildDirectory: ${{ runner.workspace }}/build
-        useVcpkgToolchainFile: true
-        cmakeAppendedArgs: '-DLOG4CXX_TEST_PROGRAM_PATH=C:\msys64\usr\bin'
+    - name: 'Configure Dependencies - Windows'
+      if: (matrix.name == 'windows-2019' || matrix.name == 'windows-2016') && steps.restore-vcpkg-cache.outputs.cache-hit != 'true'
+      id: runvcpkg
+      shell: pwsh
+      run: |
+        cd vcpkg
+        ./bootstrap-vcpkg.bat
+        ./vcpkg install apr apr-util --triplet=x64-windows
+
+    - name: 'run cmake - win'
+      if: (matrix.name == 'windows-2019' || matrix.name == 'windows-2016') 
+      shell: pwsh
+      run: |
+        $THISDIR=Get-Location
+        cd main
+        mkdir build
+        cd build
+        cmake -DLOG4CXX_TEST_PROGRAM_PATH=C:\msys64\usr\bin "-DCMAKE_TOOLCHAIN_FILE=$THISDIR/vcpkg/scripts/buildsystems/vcpkg.cmake" -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} -DCMAKE_C_COMPILER=${{ matrix.cc }} ..
+        cmake --build .
+
+    - name: 'run cmake - *nix'
+      if: matrix.name != 'windows-2019'
+      run: |
+        cd main
+        mkdir build
+        cd build
+        cmake -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} -DCMAKE_C_COMPILER=${{ matrix.cc }} ..
+        cmake --build .
 
     - name: run unit tests
       shell: pwsh
       run: |
-        cd ${{ runner.workspace }}/build
+        cd main
+        cd build
         ctest -C Debug --output-on-failure -V
diff --git a/src/main/cpp/syslogappender.cpp b/src/main/cpp/syslogappender.cpp
index f330e44..18e6478 100644
--- a/src/main/cpp/syslogappender.cpp
+++ b/src/main/cpp/syslogappender.cpp
@@ -22,10 +22,12 @@
 #include <log4cxx/spi/loggingevent.h>
 #include <log4cxx/level.h>
 #include <log4cxx/helpers/transcoder.h>
+#include <log4cxx/helpers/optionconverter.h>
 #if !defined(LOG4CXX)
 	#define LOG4CXX 1
 #endif
 #include <log4cxx/private/log4cxx_private.h>
+#include <apr_strings.h>
 
 #if LOG4CXX_HAVE_SYSLOG
 	#include <syslog.h>
@@ -64,7 +66,7 @@
 IMPLEMENT_LOG4CXX_OBJECT(SyslogAppender)
 
 SyslogAppender::SyslogAppender()
-	: syslogFacility(LOG_USER), facilityPrinting(false), sw(0)
+	: syslogFacility(LOG_USER), facilityPrinting(false), sw(0), maxMessageLength(1024)
 {
 	this->initSyslogFacilityStr();
 
@@ -72,7 +74,7 @@
 
 SyslogAppender::SyslogAppender(const LayoutPtr& layout1,
 	int syslogFacility1)
-	: syslogFacility(syslogFacility1), facilityPrinting(false), sw(0)
+	: syslogFacility(syslogFacility1), facilityPrinting(false), sw(0), maxMessageLength(1024)
 {
 	this->layout = layout1;
 	this->initSyslogFacilityStr();
@@ -80,7 +82,7 @@
 
 SyslogAppender::SyslogAppender(const LayoutPtr& layout1,
 	const LogString& syslogHost1, int syslogFacility1)
-	: syslogFacility(syslogFacility1), facilityPrinting(false), sw(0)
+	: syslogFacility(syslogFacility1), facilityPrinting(false), sw(0), maxMessageLength(1024)
 {
 	this->layout = layout1;
 	this->initSyslogFacilityStr();
@@ -306,20 +308,55 @@
 	}
 
 	LogString msg;
+	std::string encoded;
 	layout->format(msg, event, p);
 
+	Transcoder::encode(msg, encoded);
+
+	// Split up the message if it is over maxMessageLength in size.
+	// According to RFC 3164, the max message length is 1024, however
+	// newer systems(such as syslog-ng) can go up to 8k in size for their
+	// messages.  We will append (x/y) at the end of each message
+	// to indicate how far through the message we are
+	std::vector<LogString> packets;
+	if( msg.size() > maxMessageLength ){
+		LogString::iterator start = msg.begin();
+		while( start != msg.end() ){
+			LogString::iterator end = start + maxMessageLength - 12;
+			if( end > msg.end() ){
+				end = msg.end();
+			}
+			LogString newMsg = LogString( start, end );
+			packets.push_back( newMsg );
+			start = end;
+		}
+
+		int current = 1;
+		for( std::vector<LogString>::iterator it = packets.begin();
+			 it != packets.end();
+			 it++, current++ ){
+			char buf[12];
+			apr_snprintf( buf, sizeof(buf), "(%d/%d)", current, packets.size() );
+			LOG4CXX_DECODE_CHAR(str, buf);
+			it->append( str );
+		}
+	}else{
+		packets.push_back( msg );
+	}
+
 	// On the local host, we can directly use the system function 'syslog'
 	// if it is available
 #if LOG4CXX_HAVE_SYSLOG
 
 	if (sw == 0)
 	{
-		std::string sbuf;
-		Transcoder::encode(msg, sbuf);
-
-		// use of "%s" to avoid a security hole
-		::syslog(syslogFacility | event->getLevel()->getSyslogEquivalent(),
-			"%s", sbuf.c_str());
+		for( std::vector<LogString>::iterator it = packets.begin();
+			 it != packets.end();
+			 it++ ){
+			// use of "%s" to avoid a security hole
+			::syslog(syslogFacility | event->getLevel()->getSyslogEquivalent(),
+				"%s", it->c_str());
+		}
 
 		return;
 	}
@@ -334,17 +371,21 @@
 		return;
 	}
 
-	LogString sbuf(1, 0x3C /* '<' */);
-	StringHelper::toString((syslogFacility | event->getLevel()->getSyslogEquivalent()), p, sbuf);
-	sbuf.append(1, (logchar) 0x3E /* '>' */);
+	for( std::vector<LogString>::iterator it = packets.begin();
+		 it != packets.end();
+		 it++ ){
+		LogString sbuf(1, 0x3C /* '<' */);
+		StringHelper::toString((syslogFacility | event->getLevel()->getSyslogEquivalent()), p, sbuf);
+		sbuf.append(1, (logchar) 0x3E /* '>' */);
 
-	if (facilityPrinting)
-	{
-		sbuf.append(facilityStr);
+		if (facilityPrinting)
+		{
+			sbuf.append(facilityStr);
+		}
+
+		sbuf.append(*it);
+		sw->write(sbuf);
 	}
-
-	sbuf.append(msg);
-	sw->write(sbuf);
 }
 
 void SyslogAppender::activateOptions(Pool&)
@@ -361,6 +402,10 @@
 	{
 		setFacility(value);
 	}
+	else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("MAXMESSAGELENGTH"), LOG4CXX_STR("maxmessagelength")))
+	{
+		setMaxMessageLength(OptionConverter::toInt(value, 1024));
+	}
 	else
 	{
 		AppenderSkeleton::setOption(option, value);
diff --git a/src/main/include/log4cxx/net/syslogappender.h b/src/main/include/log4cxx/net/syslogappender.h
index 5acf92c..689fd2c 100644
--- a/src/main/include/log4cxx/net/syslogappender.h
+++ b/src/main/include/log4cxx/net/syslogappender.h
@@ -30,7 +30,19 @@
 {
 namespace net
 {
-/** Use SyslogAppender to send log messages to a remote syslog daemon.*/
+/**
+ * Use SyslogAppender to send log messages to a remote syslog daemon.
+ *
+ * Note that by default, this appender will split up messages that are
+ * more than 1024 bytes long, for compatability with BSD syslog(see
+ * RFC 3164).  Modern syslog implementations(e.g. syslog-ng) can accept
+ * messages much larger, and may have a default of 8k.  You may modify
+ * the default size of the messages by setting the MaxMessageLength option.
+ *
+ * When the message is too large for the current MaxMessageLength,
+ * the packet number and total # will be appended to the end of the
+ * message like this: (5/10)
+ */
 class LOG4CXX_EXPORT SyslogAppender : public AppenderSkeleton
 {
 	public:
@@ -136,6 +148,16 @@
 			return facilityPrinting;
 		}
 
+		inline void setMaxMessageLength(int maxMessageLength1)
+		{
+			maxMessageLength = maxMessageLength1;
+		}
+
+		inline int getMaxMessageLength() const
+		{
+			return maxMessageLength;
+		}
+
 	protected:
 		void initSyslogFacilityStr();
 
@@ -145,6 +167,7 @@
 		helpers::SyslogWriter* sw;
 		LogString syslogHost;
 		int syslogHostPort;
+		int maxMessageLength;
 	private:
 		SyslogAppender(const SyslogAppender&);
 		SyslogAppender& operator=(const SyslogAppender&);