diff --git a/.gitignore b/.gitignore
index cfe647e8..f6d6dd75 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,25 +4,49 @@
# User-specific files
*.suo
*.user
+*.userosscache
*.sln.docstates
-# Build results
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+# Build results
[Dd]ebug/
+[Dd]ebugPublic/
[Rr]elease/
+[Rr]eleases/
x64/
-build/
+x86/
+bld/
[Bb]in/
[Oo]bj/
-src/NLog.Targets.Syslog/lib
-src/NLog.Targets.Syslog/deploy
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+artifacts/
+
*_i.c
*_p.c
+*_i.h
*.ilk
*.meta
*.obj
@@ -42,13 +66,17 @@ src/NLog.Targets.Syslog/deploy
*.vssscc
.builds
*.pidb
-*.log
+*.svclog
*.scc
+# Chutzpah Test files
+_Chutzpah*
+
# Visual C++ cache files
ipch/
*.aps
*.ncb
+*.opendb
*.opensdf
*.sdf
*.cachefile
@@ -57,6 +85,10 @@ ipch/
*.psess
*.vsp
*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
# Guidance Automation Toolkit
*.gpState
@@ -64,6 +96,10 @@ ipch/
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
# TeamCity is a build add-in
_TeamCity*
@@ -72,8 +108,16 @@ _TeamCity*
*.dotCover
# NCrunch
-*.ncrunch*
+_NCrunch_*
.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
# Installshield output folder
[Ee]xpress/
@@ -92,65 +136,115 @@ DocProject/Help/html
publish/
# Publish Web Output
-*.Publish.xml
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
-
-# NuGet Packages Directory
-## TODO: If you have NuGet Package Restore enabled, uncomment the next line
-packages/
-
-# Windows Azure Build Output
-csx
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
*.build.csdef
-# Windows Store app package directory
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
# Others
-sql/
-*.Cache
ClientBin/
-[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
-*.[Pp]ublish.xml
+*.dbproj.schemaview
*.pfx
*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
# RIA/Silverlight projects
Generated_Code/
-# Backup & report files from converting an old project file to a newer
-# Visual Studio version. Backup files are not needed, because we have git ;-)
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
-App_Data/*.mdf
-App_Data/*.ldf
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
-#LightSwitch generated files
-GeneratedArtifacts/
-_Pvt_Extensions/
-ModelManifest.xml
+# Visual Studio 6 build log
+*.plg
-# =========================
-# Windows detritus
-# =========================
+# Visual Studio 6 workspace options file
+*.opt
-# Windows image file caches
-Thumbs.db
-ehthumbs.db
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
-# Folder config file
-Desktop.ini
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
-# Recycle Bin used on file shares
-$RECYCLE.BIN/
+# FAKE - F# Make
+.fake/
-# Mac desktop service store files
-.DS_Store
+# JetBrains Rider
+.idea/
+*.sln.iml
diff --git a/README.md b/README.md
index 89936ac3..9a8eb13e 100644
--- a/README.md
+++ b/README.md
@@ -1,27 +1,38 @@
-Syslog Target for NLog
+Syslog target for NLog
======================
+**NLog Syslog** is a custom target for **NLog**: [http://nlog-project.org](http://nlog-project.org/).
+
+It can be used with version 4.3.2 and later of NLog and allows to send logging messages to a Unix-style Syslog server.
-**NLog Syslog** is a custom target for [NLog](http://nlog-project.org/) version 4.2.2 allowing you to send logging messages to a UNIX-style Syslog server.
-## Configuration
-To use NLog Syslog, you simply wire it up as an extension in the NLog.config file and place the NLog.Targets.Syslog.dll in the same location as the NLog.dll & NLog.config files. Then use as you would any NLog target. To use TCP as transport protocol just specify protocol="tcp" in target configuration. Below is a sample NLog.config file:
+## Configuration
+To use NLog Syslog, you simply wire it up as an extension in the NLog.config file and place the NLog.Targets.Syslog.dll in the same location as the NLog.dll & NLog.config files.
+Then use as you would any NLog target.
+Below is a sample NLog.config file:
```xml
-
+
-
-
-
-
-
-
+
+
+
+ Local4
+ Rfc5424
+
+
+
+
+
+ true
+
+
+
-
-
+
```
@@ -29,60 +40,324 @@ The package is also available through NuGet. Simply search for "NLog.Targets.Sys
### Options
+This NLog target supports the standard NLog [layout](https://github.com/NLog/NLog/wiki/Layouts)
+directive to modify the log message body (Syslog packet elements are not affected).
+It provides default values for all configuration options which can be overridden
+by means of configuration settings, as shown in the example configuration above.
+A more detailed example is included in the [test application](./src/TestApp/NLog.config).
+
+#### Enforcement element
+* `splitOnNewLine` - `false` or `true` to split log entries on new line (default: `false`)
+* `transliterate` - `false` or `true` to trasliterate strings from Unicode to ASCII when the RFC allows only ASCII characters for a fields (default: `false`)
+* `replaceInvalidCharacters` - `false` or `true` to replace invalid values usually with a question mark (default: `false`)
+* `truncateFieldsToMaxLength` - `false` or `true` to truncate fields to the length specified in the RFC (default: `false`)
+* `truncateMessageTo` - a number specifying the max lenght allowed for the whole message (default: `0` i.e. do not truncate)
+
+The maximum length of a message is detailed in many RFCs that can be summarized as follow:
+
+| | MUST be supported | SHOULD be supported | MUST NOT exceed (we are limited by Int32.MaxValue)
+| :-------------------: | :-----------------: | :-------------------: | :--------------------------------------------------:
+| RFC 3164 (UDP) | 1024 B | 1024 B | 1024 B
+| RFC 6587 (TCP) | 1024 B | 1024 B | 1024 B
+| RFC 5424 (TCP/UDP) | 480 B | 2048 B | -
+| RFC 5426 (UDP/IPv4) | 480 B | 2048 B | 65535 - 60 - 8 B 1
+| RFC 5426 (UDP/IPv6) | 1180 B | 2048 B | 65535 - 40 - 8 B 1
+| RFC 5426 (UDP/IPv6) | 1180 B | 2048 B | (2^32 - 1) - 40 - 8 B 1 2
+| RFC 5425 (TLS/IPv4) | 2048 B | 8192 B | 65535 - 60 - 60 B 1
+| RFC 5425 (TLS/IPv6) | 2048 B | 8192 B | 65535 - 40 - 60 B 1
+| RFC 5425 (TLS/IPv6) | 2048 B | 8192 B | (2^32 - 1) - 40 - 60 B 1 2
+
+1 IP payload - max IP header - max protocol header
+2 Using jumbograms
+
+#### Message builder element
+* `facility` - facility name (default: `Local1`)
+* `rfc` - `rfc3164` or `rfc5424` (default: `rfc5424`)
+* `rfc3164` - settings related to RFC 3164:
+ * `hostname` ([Layout](http://github.com/NLog/NLog/wiki/Layouts)) - the HOSTNAME part (default: the hostname of the computer that is creating the message)
+ * `tag` ([Layout](http://github.com/NLog/NLog/wiki/Layouts)) - the TAG part (default: the name of the assembly that is creating the message)
+* `rfc5424` - settings related to RFC 5424:
+ * `hostname` ([Layout](http://github.com/NLog/NLog/wiki/Layouts)) - the HOSTNAME field of the HEADER part (default: the hostname of the computer that is creating the message)
+ * `appName` ([Layout](http://github.com/NLog/NLog/wiki/Layouts)) - the APPNAME field of the HEADER part (default: the name of the assembly that is creating the message)
+ * `procId` ([Layout](http://github.com/NLog/NLog/wiki/Layouts)) - the PROCID field of the HEADER part (default: `-`)
+ * `msgId` ([Layout](http://github.com/NLog/NLog/wiki/Layouts)) - the MSGID field of the HEADER part (default: `-`)
+ * `structuredData` - the STRUCTURED-DATA part containing the SD-ELEMENTs each composed by an SD-ID ([Layout](http://github.com/NLog/NLog/wiki/Layouts))
+ and optional SD-PARAM fields, i.e. the PARAM-NAME ([Layout](http://github.com/NLog/NLog/wiki/Layouts)) and
+ PARAM-VALUE ([Layout](http://github.com/NLog/NLog/wiki/Layouts)) fields (default: `-`).
+ The fromEventProperties attribute allows to use [log event properties data](http://github.com/NLog/NLog/wiki/EventProperties-Layout-Renderer)
+ enabling different STRUCTURED-DATA for each log message
+ * `disableBom` - `true` or `false` to handle RSyslog [issue 284](http://github.com/rsyslog/rsyslog/issues/284) (default: `false`)
+
+#### Message transmitter element
+* `protocol` - `udp` or `tcp` (default: `udp`)
+* `udpProtocol` - settings related to UDP:
+ * `server` - IP or hostname of the Syslog server (default: `127.0.0.1`)
+ * `port` - port the Syslog server is listening on (default: `514`)
+* `tcpProtocol` - settings related to TCP:
+ * `server` - IP or hostname of the Syslog server (default: `127.0.0.1`)
+ * `port` - port the Syslog server is listening on (default: `514`)
+ * `useTls` - `false` or `true` (default: `true`)
+ * `framing` - `nonTransparent` or `octectCounting` (default: `octectCounting`)
+
+
+
+
+
+
+
+
+# Test bench
+ 1. `[HOST]` Download VirtualBox and Vagrant and install them
+ 2. `[HOST]` Download an [Ubuntu Vagrant box](http://cloud-images.ubuntu.com/vagrant/)
+ 3. `[HOST]` Create a Vagrantfile in the same folder of the downloaded box
+
+ ```ruby
+ Vagrant.configure("2") do |config|
+ config.vm.box = "ubuntu/trusty64"
+ config.ssh.host = "127.0.0.1"
+ config.ssh.username = "vagrant"
+ config.ssh.password = "vagrant"
+ config.vm.network :forwarded_port, id: 'ssh', guest: 22, host: 2222, auto_correct: false
+ config.vm.network :forwarded_port, guest: 514, host: 1514, protocol: "tcp", auto_correct: false
+ config.vm.network :forwarded_port, guest: 514, host: 1514, protocol: "udp", auto_correct: false
+ end
+ ```
+
+ 5. `[HOST]` Add the box to the list
+
+ ```shell
+ vagrant box add .\ubuntuvagrant.box --name 'ubuntu/trusty64'
+ vagrant box list
+ ```
+
+ 6. `[HOST]` Start the VM
+
+ ```shell
+ vagrant up
+ ```
+
+ 7. `[HOST]` Connect to the VM with SSH on port 2222
+ 8. `[GUEST]` Switch to the root user
+
+ ```shell
+ su
+ ```
+
+ 9. `[GUEST]` Uncomment the following `/etc/rsyslog.conf` lines:
+
+ ```
+ #$ModLoad imudp
+ #$UDPServerRun 514
+ ```
+ ```
+ #$ModLoad imtcp
+ #$InputTCPServerRun 514
+ ```
+
+10. `[GUEST]` Add the following `/etc/rsyslog.d/50-default.conf` line under the `user.*` one (prefixing a path with the minus sign omits flushing after every log event)
+
+ ```
+ local4.* /var/log/local4.log
+ ```
+
+11. `[GUEST]` Restart Syslog service
+
+ ```shell
+ service rsyslog restart
+ ```
+
+12. `[HOST]` Restart the VM
-This NLog target provides default values for all configuration options.
-Optionally, your configuration can override them using attributes on
-`target`, as shown in the example configuration above.
+ ```shell
+ vagrant reload
+ ```
-#### Destination
+13. `[GUEST]` Make sure rsyslog is running
-* `syslogserver`: IP or hostname (default: `127.0.0.1`)
-* `port`: Port of syslog listener (default: `514`)
-* `protocol`: `udp` or `tcp` (default: `udp`)
-* `ssl`: `false` or `true`; TCP only (default: `false`)
-* `rfc`: Rfc compatibility for syslog message `Rfc3164` or `Rfc5424` (default: `Rfc3164`)
+ ```shell
+ ps -A | grep rsyslog
+ ```
-#### Syslog packet elements
+14. `[GUEST]` Check the rsyslog configuration
-Messages are sent using the format (framing) called syslog, which is
-defined in [RFC 3164](http://www.ietf.org/rfc/rfc3164.txt) or
-[RFC 5424](http://tools.ietf.org/html/rfc5424). In addition
-to a timestamp and the log message, RFC 3164 syslog messages include
-other elements: sending device name (such as the machine's hostname),
-sending app/component name (called "tag" in the RFC), facility, and
-severity.
+ ```shell
+ rsyslogd -N1
+ ```
-The following syslog elements can be overridden for RFC 3164:
+15. `[GUEST]` Check the Linux system log for rsyslog errors
-* `machinename` ([Layout](https://github.com/NLog/NLog/wiki/Layouts)): name of sending system or entity (default: machine
- [hostname](http://msdn.microsoft.com/en-us/library/system.net.dns.gethostname(v=vs.110).aspx)).
-For example, ${machinename}
-* `sender` ([Layout](https://github.com/NLog/NLog/wiki/Layouts)): name of sending component or application (default:
- [calling method](http://msdn.microsoft.com/en-us/library/system.reflection.assembly.getcallingassembly(v=vs.110).aspx)).
-For example, ${logger}
-* `facility`: facility name (default: `Local1`)
+ ```shell
+ cat /var/log/syslog | grep rsyslog
+ ```
-For example, to make logs from multiple systems use the same device
-identifier (rather than each system's hostname), one could set
-`machinename` to `app-cloud`. The logs from different systems would
-all appear to be from the same single entity called `app-cloud`.
+16. `[GUEST]` Perform a local test
-The following additional syslog elements can be overridden for [RFC 5424](http://tools.ietf.org/html/rfc5424):
+ ```shell
+ logger --server 127.0.0.1 --port 514 --priority local4.error "TCP local test"
+ logger --server 127.0.0.1 --port 514 --priority local4.warning --udp "UDP local test"
+ tail -3 /var/log/syslog
+ tail -3 /var/log/local4.log
+ ```
-* `procid` ([Layout](https://github.com/NLog/NLog/wiki/Layouts)): [identifier](http://tools.ietf.org/html/rfc5424#section-6.2.6) (numeric or alphanumeric) of sending entity
-(default: -). For example, ${processid} or ${processname}
-* `msgid` ([Layout](https://github.com/NLog/NLog/wiki/Layouts)): [message type identifier](http://tools.ietf.org/html/rfc5424#section-6.2.7) (numeric or alphanumeric) of sending entity
-(default: -). For example, ${callsite}
-* `structureddata` ([Layout](https://github.com/NLog/NLog/wiki/Layouts)): [additional data](http://tools.ietf.org/html/rfc5424#section-6.3) of sending entity (default: -).
-For example, [thread@12345 id="${threadid}" name="${threadname}"][mydata2@12345 num="1" code="mycode"]
+17. `[GUEST]` Prepare for a remote test
-#### Log message body
+ ```shell
+ tail -f /var/log/syslog
+ ```
-This target supports the standard NLog
-[layout](https://github.com/NLog/NLog/wiki/Layouts) directive to modify
-the log message body. The syslog packet elements are not affected.
+ OR
+ ```shell
+ tcpdump port 514 -vv
+ ```
+
+18. `[HOST]` Perform a remote test
+
+ ```shell
+ telnet 127.0.0.1 1514
+ ```
+
+19. `[HOST]` Perform a remote test with the NLog target (configuring it to use the Local4 facility)
+
+
+
+
+
+
+
+
+# Syslog message format
+Messages are built using the format defined in
+[RFC 3164](http://tools.ietf.org/html/rfc3164) or
+[RFC 5424](http://tools.ietf.org/html/rfc5424).
+They are then sent using one of the protocols defined in
+[RFC 5426](http://tools.ietf.org/html/rfc5426) or
+[RFC 6587](http://tools.ietf.org/html/rfc6587) or
+[RFC 5425](http://tools.ietf.org/html/rfc5425).
+
+
+### RFC 3164
+There are no set requirements on the contents of the Syslog message: the payload of any Syslog message must be considered to be a valid Syslog message.
+It is, however, recommended for the Syslog message to have all the parts described here.
+
+#### Conventions
+* `SPACE`: the ASCII value `dec 32` / `hex 20`
+* `PRINTUSASCII`: ASCII values in the range `dec [33, 126]` / `hex [21, 7E]`
+
+#### Message parts
+A Syslog message is at least 1 and at most 1024 characters long and the only allowed characters are `SPACE` or `PRINTUSASCII`
+
+```
+SYSLOG MESSAGE = PRI HEADER SPACE MSG
+
+PRI = < PRIVAL >
+ PRIVAL = FACILITY * 8 + SEVERITY
+ FACILITY
+ A number between 0 and 23
+ SEVERITY
+ A number between 0 and 7
+
+HEADER = TIMESTAMP space HOSTNAME (only SPACE or PRINTUSASCII allowed)
+ TIMESTAMP
+ "Mmm dd hh:mm:ss" using a local timezone
+ Space-padding in dd, zero-padding in hh, mm and ss
+ HOSTNAME
+ Hostname or IPv4 address or IPv6 address of the sender machine
+
+MSG = TAG CONTENT
+ TAG
+ Name of the sender program or process
+ An alphanumeric string not exceeding 32 characters
+ CONTENT
+ Detailed information of the event
+ A non-alphanumeric character followed by SPACE or PRINTUSASCII characters
+```
+
+#### Examples
+
+* `<34>Oct 11 00:14:05 mymachine su: 'su root' failed for lonvick on /dev/pts/8`
+* `<13>Feb 5 17:32:18 10.0.0.99 myTag Use the BFG!`
+
+
+### RFC 5424
+
+
+#### Conventions
+* `(section)`: brackets are used to indicate that a section is optional
+* `NILVALUE`: the hyphen i.e. ASCII value dec 45 / hex 2D
+* `SPACE`: the ASCII value `dec 32` / `hex 20`
+* `PRINTUSASCII`: ASCII values in the range `dec [33, 126]` / `hex [21, 7E]`
+* `SAFEPRINTUSASCII`: PRINTUSASCII except `=`, `]`, `"`
+
+#### Message parts
+A Syslog message is at most 480 to 2048 or more bytes
+
+This is the detail of the format:
+```
+SYSLOG MESSAGE = HEADER SPACE STRUCTURED-DATA (SPACE MSG)
+
+HEADER = PRI VERSION SPACE TIMESTAMP SPACE HOSTNAME SPACE APPNAME SPACE PROCID SPACE MSGID
+ PRI = < PRIVAL >
+ PRIVAL = FACILITY * 8 + SEVERITY
+ FACILITY
+ A number between 0 and 23
+ SEVERITY
+ A number between 0 and 7
+ VERSION
+ A nonzero digit followed by 0 to 2 digits (current version is 1)
+ TIMESTAMP
+ NILVALUE or RFC3339 timestamp with an optional 1 to 6 digits second fraction part
+ HOSTNAME
+ NILVALUE or 1 to 255 PRINTUSASCII
+ The FQDN or IPv4 address or IPv6 address or hostname of the sender machine
+ APPNAME
+ NILVALUE or 1 to 48 PRINTUSASCII
+ The device or application sending the Syslog message
+ PROCID
+ NILVALUE or 1 to 128 PRINTUSASCII
+ A change indicates a discontinuity in Syslog reporting
+ Often the process name or id or an identifier of the group the Syslog message belongs to
+ MSGID
+ NILVALUE or 1 to 32 PRINTUSASCII
+ The type of message that should be the same for events with the same semantics
+
+STRUCTURED-DATA = NILVALUE or one or more SD-ELEMENT
+ SD-ELEMENT = [ SD-ID (one or more SPACE SD-PARAM) ]
+ SD-ID
+ At most 32 SAFEPRINTUSASCII specifying a unique identifier within STRUCTUREDDATA
+ The identifier can be a CUSTOMID or IANAID:
+ CUSTOMID = NAME @ PEN
+ NAME
+ SAFEPRINTUSASCII except @
+ PEN
+ A private enterprise number
+ Digits or digits separated by periods
+ IANAID = timeQuality or origin or meta
+ timeQuality
+ Parameters are tzKnown, isSynced, syncAccuracy
+ origin
+ Parameters are ip, enterpriseId, software, swVersion
+ meta
+ Parameters are sequenceId, sysUpTime, language
+ SD-PARAM = PARAM-NAME = " PARAM-VALUE "
+ PARAM-NAME
+ 1 to 32 SAFEPRINTUSASCII
+ PARAM-VALUE
+ UTF8 STRING with ", \ and ] escaped as \", \\ and \]
+
+MSG = MSGANY or MSGUTF8
+ MSGANY
+ Zero or more bytes
+ MSGUTF8 = BOM UTF8STRING
+ BOM
+ The hex value EFBBBF
+ UTF8STRING
+ A UTF8 compliant string
+```
-## NLog
+#### Examples
-See more about NLog at: http://nlog-project.org
+* `<34>1 2003-10-11T22:14:15.003Z mymachine.example.com su - ID47 - BOM'su root' failed for lonvick on /dev/pts/8`
+* `<165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - - %% It's time to make the do-nuts.`
+* `<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"] BOMAn application event log entry...`
+* `<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"][examplePriority@32473 class="high"]`
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog.sln b/src/NLog.Targets.Syslog.sln
index 2deadff3..843ecb99 100644
--- a/src/NLog.Targets.Syslog.sln
+++ b/src/NLog.Targets.Syslog.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
-VisualStudioVersion = 14.0.24720.0
+VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NLog.Targets.Syslog", "NLog.Targets.Syslog\NLog.Targets.Syslog.csproj", "{D888EE7E-4394-4FB1-9B37-29513FF8A91A}"
EndProject
@@ -10,39 +10,24 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9B0D1054-6E68-4208-97BC-12F254CF3754}"
ProjectSection(SolutionItems) = preProject
License.txt = License.txt
+ schemas\NLog.Targets.Syslog.xsd = schemas\NLog.Targets.Syslog.xsd
..\README.md = ..\README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
- Debug|Mixed Platforms = Debug|Mixed Platforms
- Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
- Release|Mixed Platforms = Release|Mixed Platforms
- Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D888EE7E-4394-4FB1-9B37-29513FF8A91A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D888EE7E-4394-4FB1-9B37-29513FF8A91A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D888EE7E-4394-4FB1-9B37-29513FF8A91A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {D888EE7E-4394-4FB1-9B37-29513FF8A91A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
- {D888EE7E-4394-4FB1-9B37-29513FF8A91A}.Debug|x86.ActiveCfg = Debug|Any CPU
{D888EE7E-4394-4FB1-9B37-29513FF8A91A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D888EE7E-4394-4FB1-9B37-29513FF8A91A}.Release|Any CPU.Build.0 = Release|Any CPU
- {D888EE7E-4394-4FB1-9B37-29513FF8A91A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {D888EE7E-4394-4FB1-9B37-29513FF8A91A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
- {D888EE7E-4394-4FB1-9B37-29513FF8A91A}.Release|x86.ActiveCfg = Release|Any CPU
- {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Debug|Any CPU.ActiveCfg = Debug|x86
- {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
- {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Debug|Mixed Platforms.Build.0 = Debug|x86
- {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Debug|x86.ActiveCfg = Debug|x86
- {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Debug|x86.Build.0 = Debug|x86
- {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Release|Any CPU.ActiveCfg = Release|x86
- {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Release|Mixed Platforms.ActiveCfg = Release|x86
- {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Release|Mixed Platforms.Build.0 = Release|x86
- {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Release|x86.ActiveCfg = Release|x86
- {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Release|x86.Build.0 = Release|x86
+ {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FEDBC211-287E-4D64-B111-594D1CB7C54B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/NLog.Targets.Syslog/MessageCreation/EncodingSet.cs b/src/NLog.Targets.Syslog/MessageCreation/EncodingSet.cs
new file mode 100644
index 00000000..b648a14c
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageCreation/EncodingSet.cs
@@ -0,0 +1,16 @@
+using System.Text;
+
+namespace NLog.Targets.Syslog.MessageCreation
+{
+ internal class EncodingSet
+ {
+ public ASCIIEncoding Ascii { get; }
+ public UTF8Encoding Utf8 { get; }
+
+ public EncodingSet(bool enableBom)
+ {
+ Ascii = new ASCIIEncoding();
+ Utf8 = new UTF8Encoding(enableBom);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageCreation/EnumerableExtension.cs b/src/NLog.Targets.Syslog/MessageCreation/EnumerableExtension.cs
new file mode 100644
index 00000000..45d111ed
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageCreation/EnumerableExtension.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+
+namespace NLog.Targets.Syslog.MessageCreation
+{
+ internal static class EnumerableExtension
+ {
+ public static void ForEach(this IEnumerable enumerable, Action action)
+ {
+ foreach (var item in enumerable)
+ action(item);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/SyslogFacility.cs b/src/NLog.Targets.Syslog/MessageCreation/Facility.cs
similarity index 93%
rename from src/NLog.Targets.Syslog/SyslogFacility.cs
rename to src/NLog.Targets.Syslog/MessageCreation/Facility.cs
index 8ef0b577..f08aad75 100644
--- a/src/NLog.Targets.Syslog/SyslogFacility.cs
+++ b/src/NLog.Targets.Syslog/MessageCreation/Facility.cs
@@ -1,9 +1,7 @@
-// ReSharper disable CheckNamespace
-namespace NLog.Targets
-// ReSharper enable CheckNamespace
+namespace NLog.Targets.Syslog.MessageCreation
{
/// Syslog facilities
- public enum SyslogFacility
+ public enum Facility
{
/// Kernel messages
Kernel = 0,
diff --git a/src/NLog.Targets.Syslog/MessageCreation/MessageBuilder.cs b/src/NLog.Targets.Syslog/MessageCreation/MessageBuilder.cs
new file mode 100644
index 00000000..ed004ae9
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageCreation/MessageBuilder.cs
@@ -0,0 +1,46 @@
+using NLog.Layouts;
+using NLog.Targets.Syslog.Policies;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace NLog.Targets.Syslog.MessageCreation
+{
+ /// Allows to build Syslog messages
+ public abstract class MessageBuilder
+ {
+ private SplitOnNewLinePolicy splitOnNewLinePolicy;
+
+ /// The Syslog facility to log from (its name e.g. local0 or local7)
+ protected Facility Facility { get; set; }
+
+ internal virtual void Initialize(Enforcement enforcement, Facility facility)
+ {
+ splitOnNewLinePolicy = new SplitOnNewLinePolicy(enforcement);
+ Facility = facility;
+ }
+
+ internal IEnumerable> BuildMessages(LogEventInfo logEvent, Layout layout)
+ {
+ var pri = Pri(Facility, (Severity)logEvent.Level);
+ var logEntries = LogEntries(logEvent, layout).ToList();
+ var toBeSent = logEntries.Select(logEntry => BuildMessage(logEvent, pri, logEntry));
+ return toBeSent;
+ }
+
+ internal abstract IEnumerable BuildMessage(LogEventInfo logEvent, string pri, string logEntry);
+
+ private static string Pri(Facility facility, Severity severity)
+ {
+ var priVal = (int)facility * 8 + (int)severity;
+ var priValString = priVal.ToString(CultureInfo.InvariantCulture);
+ return $"<{priValString}>";
+ }
+
+ private IEnumerable LogEntries(LogEventInfo logEvent, Layout layout)
+ {
+ var originalLogEntry = layout.Render(logEvent);
+ return splitOnNewLinePolicy.IsApplicable() ? splitOnNewLinePolicy.Apply(originalLogEntry) : new[] { originalLogEntry };
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageCreation/MessageBuildersFacade.cs b/src/NLog.Targets.Syslog/MessageCreation/MessageBuildersFacade.cs
new file mode 100644
index 00000000..2f2d806f
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageCreation/MessageBuildersFacade.cs
@@ -0,0 +1,49 @@
+using NLog.Layouts;
+using NLog.Targets.Syslog.Policies;
+using System.Collections.Generic;
+
+namespace NLog.Targets.Syslog.MessageCreation
+{
+ public class MessageBuildersFacade
+ {
+ private MessageBuilder activeBuilder;
+ private readonly Dictionary builders;
+
+ /// The Syslog facility to log from (its name e.g. local0 or local7)
+ public Facility Facility { get; set; }
+
+ /// The Syslog protocol RFC to be followed
+ public RfcNumber Rfc { get; set; }
+
+ /// RFC 3164 related fields
+ public Rfc3164 Rfc3164 { get; set; }
+
+ /// RFC 5424 related fields
+ public Rfc5424 Rfc5424 { get; set; }
+
+ /// Builds a new instance of the MessageBuildersFacade class
+ public MessageBuildersFacade()
+ {
+ Facility = Facility.Local1;
+ Rfc = RfcNumber.Rfc5424;
+ Rfc3164 = new Rfc3164();
+ Rfc5424 = new Rfc5424();
+ builders = new Dictionary
+ {
+ { RfcNumber.Rfc3164, Rfc3164 },
+ { RfcNumber.Rfc5424, Rfc5424 }
+ };
+ }
+
+ internal void Initialize(Enforcement enforcement)
+ {
+ activeBuilder = builders[Rfc];
+ activeBuilder.Initialize(enforcement, Facility);
+ }
+
+ internal IEnumerable> BuildMessages(LogEventInfo logEvent, Layout layout)
+ {
+ return activeBuilder.BuildMessages(logEvent, layout);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageCreation/Rfc3164.cs b/src/NLog.Targets.Syslog/MessageCreation/Rfc3164.cs
new file mode 100644
index 00000000..1518cbe5
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageCreation/Rfc3164.cs
@@ -0,0 +1,86 @@
+using NLog.Config;
+using NLog.Layouts;
+using NLog.Targets.Syslog.Policies;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Net;
+using System.Reflection;
+using System.Text;
+
+namespace NLog.Targets.Syslog.MessageCreation
+{
+ /// Allows to build Syslog messages compliant with RFC 3164
+ [NLogConfigurationItem]
+ public class Rfc3164 : MessageBuilder
+ {
+ private PlainHostnamePolicySet hostnamePolicySet;
+ private TagPolicySet tagPolicySet;
+ private PlainContentPolicySet plainContentPolicySet;
+ private EncodedContentPolicy encodedContentPolicy;
+ private const string TimestampFormat = "{0:MMM} {0,11:d HH:mm:ss}";
+ private static readonly byte[] SpaceBytes = { 0x20 };
+
+ /// The HOSTNAME field of the HEADER part
+ public Layout Hostname { get; set; }
+
+ /// The TAG field of the MSG part
+ public Layout Tag { get; set; }
+
+ /// Builds a new instance of the Rfc3164 class
+ public Rfc3164()
+ {
+ Hostname = Dns.GetHostName();
+ Tag = Assembly.GetCallingAssembly().GetName().Name;
+ }
+
+ internal override void Initialize(Enforcement enforcement, Facility facility)
+ {
+ base.Initialize(enforcement, facility);
+ hostnamePolicySet = new PlainHostnamePolicySet(enforcement);
+ tagPolicySet = new TagPolicySet(enforcement);
+ plainContentPolicySet = new PlainContentPolicySet(enforcement);
+ encodedContentPolicy = new EncodedContentPolicy(enforcement);
+ }
+
+ internal override IEnumerable BuildMessage(LogEventInfo logEvent, string pri, string logEntry)
+ {
+ var encoding = new ASCIIEncoding();
+ var msgPrefixBytes = PriBytes(pri, encoding)
+ .Concat(HeaderBytes(logEvent, encoding))
+ .Concat(SpaceBytes)
+ .ToArray();
+ var msgBytes = MsgBytes(logEvent, logEntry, msgPrefixBytes.Length, encoding);
+ return msgPrefixBytes.Concat(msgBytes);
+ }
+
+ private static IEnumerable PriBytes(string pri, Encoding encoding)
+ {
+ return encoding.GetBytes(pri);
+ }
+
+ private IEnumerable HeaderBytes(LogEventInfo logEvent, Encoding encoding)
+ {
+ var timestamp = string.Format(CultureInfo.InvariantCulture, TimestampFormat, logEvent.TimeStamp);
+ var hostname = hostnamePolicySet.Apply(Hostname.Render(logEvent));
+ var header = $"{timestamp} {hostname}";
+ return encoding.GetBytes(header);
+ }
+
+ private IEnumerable MsgBytes(LogEventInfo logEvent, string logEntry, int msgPrefixSize, Encoding encoding)
+ {
+ var tag = tagPolicySet.Apply(Tag.Render(logEvent));
+ var tagBytes = encoding.GetBytes(tag);
+ var contentPrefixLength = msgPrefixSize + tag.Length;
+ var contentBytes = ContentBytes(logEntry, contentPrefixLength, encoding);
+ return tagBytes.Concat(contentBytes);
+ }
+
+ private IEnumerable ContentBytes(string logEntry, int contentPrefixLength, Encoding encoding)
+ {
+ var plainContent = plainContentPolicySet.Apply(logEntry);
+ var encodedContent = encoding.GetBytes(plainContent);
+ return encodedContentPolicy.Apply(encodedContent, contentPrefixLength);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageCreation/Rfc5424.cs b/src/NLog.Targets.Syslog/MessageCreation/Rfc5424.cs
new file mode 100644
index 00000000..ee12df23
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageCreation/Rfc5424.cs
@@ -0,0 +1,117 @@
+using NLog.Config;
+using NLog.Layouts;
+using NLog.Targets.Syslog.Policies;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Reflection;
+
+namespace NLog.Targets.Syslog.MessageCreation
+{
+ /// Allows to build Syslog messages compliant with RFC 5424
+ [NLogConfigurationItem]
+ public class Rfc5424 : MessageBuilder
+ {
+ private readonly string defaultHostname;
+ private readonly string defaultAppName;
+ private const string DefaultVersion = "1";
+ private const string NilValue = "-";
+ private FqdnHostnamePolicySet hostnamePolicySet;
+ private AppNamePolicySet appNamePolicySet;
+ private ProcIdPolicySet procIdPolicySet;
+ private MsgIdPolicySet msgIdPolicySet;
+ private MsgWithoutPreamblePolicy msgWithoutPreamblePolicy;
+ private const string TimestampFormat = "{0:yyyy-MM-ddTHH:mm:ss.ffffffK}";
+ private static readonly byte[] SpaceBytes = { 0x20 };
+
+ /// The VERSION field of the HEADER part
+ public string Version { get; }
+
+ /// The HOSTNAME field of the HEADER part
+ public Layout Hostname { get; set; }
+
+ /// The APPNAME field of the HEADER part
+ public Layout AppName { get; set; }
+
+ /// The PROCID field of the HEADER part
+ public Layout ProcId { get; set; }
+
+ /// The MSGID field of the HEADER part
+ public Layout MsgId { get; set; }
+
+ /// The STRUCTURED-DATA part
+ public StructuredData StructuredData { get; set; }
+
+ /// Whether to remove or not BOM in the MSG part
+ /// RSyslog issue #284
+ public bool DisableBom { get; set; }
+
+ /// Builds a new instance of the Rfc5424 class
+ public Rfc5424()
+ {
+ defaultHostname = HostFqdn();
+ defaultAppName = Assembly.GetCallingAssembly().GetName().Name;
+ Version = DefaultVersion;
+ Hostname = defaultHostname;
+ AppName = defaultAppName;
+ ProcId = NilValue;
+ MsgId = NilValue;
+ StructuredData = new StructuredData();
+ DisableBom = false;
+ }
+
+ internal override void Initialize(Enforcement enforcement, Facility facility)
+ {
+ base.Initialize(enforcement, facility);
+ hostnamePolicySet = new FqdnHostnamePolicySet(enforcement, defaultHostname);
+ appNamePolicySet = new AppNamePolicySet(enforcement, defaultAppName);
+ procIdPolicySet = new ProcIdPolicySet(enforcement);
+ msgIdPolicySet = new MsgIdPolicySet(enforcement);
+ msgWithoutPreamblePolicy = new MsgWithoutPreamblePolicy(enforcement);
+ StructuredData.Initialize(enforcement);
+ }
+
+ internal override IEnumerable BuildMessage(LogEventInfo logEvent, string pri, string logEntry)
+ {
+ var encodings = new EncodingSet(!DisableBom);
+
+ var msgPrefixBytes = HeaderBytes(pri, logEvent, encodings)
+ .Concat(SpaceBytes)
+ .Concat(StructuredData.Bytes(logEvent, encodings))
+ .Concat(SpaceBytes)
+ .ToArray();
+ var msgBytes = MsgBytes(logEntry, msgPrefixBytes.Length, encodings);
+ return msgPrefixBytes.Concat(msgBytes);
+ }
+
+ private static string HostFqdn()
+ {
+ var hostname = Dns.GetHostName();
+ var domainName = IPGlobalProperties.GetIPGlobalProperties().DomainName;
+ var domainAsSuffix = $".{domainName}";
+ return hostname.EndsWith(domainAsSuffix) ? hostname : $"{hostname}{domainAsSuffix}";
+ }
+
+ private IEnumerable HeaderBytes(string pri, LogEventInfo logEvent, EncodingSet encodings)
+ {
+ var timestamp = string.Format(CultureInfo.InvariantCulture, TimestampFormat, logEvent.TimeStamp);
+ var hostname = hostnamePolicySet.Apply(Hostname.Render(logEvent));
+ var appName = appNamePolicySet.Apply(AppName.Render(logEvent));
+ var procId = procIdPolicySet.Apply(ProcId.Render(logEvent));
+ var msgId = msgIdPolicySet.Apply(MsgId.Render(logEvent));
+ var header = $"{pri}{Version} {timestamp} {hostname} {appName} {procId} {msgId}";
+ return encodings.Ascii.GetBytes(header);
+ }
+
+ private IEnumerable MsgBytes(string logEntry, int msgPrefixLength, EncodingSet encodings)
+ {
+ var preambleBytes = encodings.Utf8.GetPreamble();
+ var logEntryBytes = encodings.Utf8.GetBytes(logEntry);
+ var msgWithoutPreamblePrefixLength = msgPrefixLength + preambleBytes.Length;
+ var msgWithoutPreambleBytes = msgWithoutPreamblePolicy.Apply(logEntryBytes, msgWithoutPreamblePrefixLength);
+ return preambleBytes.Concat(msgWithoutPreambleBytes);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageCreation/RfcNumber.cs b/src/NLog.Targets.Syslog/MessageCreation/RfcNumber.cs
new file mode 100644
index 00000000..a96ccf9d
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageCreation/RfcNumber.cs
@@ -0,0 +1,9 @@
+namespace NLog.Targets.Syslog.MessageCreation
+{
+ /// The Syslog protocol RFC to be followed
+ public enum RfcNumber
+ {
+ Rfc3164 = 3164,
+ Rfc5424 = 5424
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageCreation/SdElement.cs b/src/NLog.Targets.Syslog/MessageCreation/SdElement.cs
new file mode 100644
index 00000000..fce788b2
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageCreation/SdElement.cs
@@ -0,0 +1,74 @@
+using NLog.Config;
+using NLog.Targets.Syslog.Policies;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace NLog.Targets.Syslog.MessageCreation
+{
+ /// A Syslog SD-ELEMENT field
+ [NLogConfigurationItem]
+ public class SdElement
+ {
+ private SdIdToInvalidParamNamePattern sdIdToInvalidParamNamePattern;
+ private static readonly byte[] LeftBracketBytes = { 0x5B };
+ private static readonly byte[] RightBracketBytes = { 0x5D };
+
+ /// The SD-ID field of an SD-ELEMENT field in the STRUCTURED-DATA part
+ public SdId SdId { get; set; }
+
+ /// The SD-PARAM fields belonging to an SD-ELEMENT field in the STRUCTURED-DATA part
+ [ArrayParameter(typeof(SdParam), nameof(SdParam))]
+ public IList SdParams { get; set; }
+
+ /// Builds a new instance of the SdElement class
+ public SdElement()
+ {
+ sdIdToInvalidParamNamePattern = new SdIdToInvalidParamNamePattern();
+ SdParams = new List();
+ }
+
+ internal void Initialize(Enforcement enforcement)
+ {
+ SdId.Initialize(enforcement);
+ SdParams.ForEach(sdParam => sdParam.Initialize(enforcement));
+ }
+
+ internal static string ToString(IEnumerable sdElements)
+ {
+ return sdElements.Aggregate(string.Empty, (acc, curr) => acc.ToString() + curr.ToString());
+ }
+
+ public override string ToString()
+ {
+ return $"[{SdId}{SdParam.ToString(SdParams)}]";
+ }
+
+ internal static IEnumerable Bytes(IEnumerable sdElements, LogEventInfo logEvent, EncodingSet encodings)
+ {
+ var elements = sdElements.ToList();
+
+ var ids = elements.Select(x => x.SdId);
+ var encodedIds = SdId.Bytes(ids, logEvent, encodings).ToList();
+
+ var encodedparamLists = elements
+ .Select(x =>
+ {
+ var renderedId = x.SdId.Render(logEvent);
+ var invalidParamNames = SdIdToInvalidParamNamePattern.Map(renderedId);
+ return SdParam.Bytes(x.SdParams, logEvent, invalidParamNames, encodings);
+ })
+ .ToList();
+
+ return elements.SelectMany((e, i) => Bytes(encodedIds[i], encodedparamLists[i]));
+ }
+
+ private static IEnumerable Bytes(IEnumerable sdIdBytes, IEnumerable sdParamsBytes)
+ {
+ return LeftBracketBytes
+ .Concat(LeftBracketBytes)
+ .Concat(sdIdBytes)
+ .Concat(sdParamsBytes)
+ .Concat(RightBracketBytes);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageCreation/SdId.cs b/src/NLog.Targets.Syslog/MessageCreation/SdId.cs
new file mode 100644
index 00000000..6a2eaf91
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageCreation/SdId.cs
@@ -0,0 +1,54 @@
+using NLog.Layouts;
+using NLog.Targets.Syslog.Policies;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace NLog.Targets.Syslog.MessageCreation
+{
+ public class SdId : SimpleLayout
+ {
+ private static readonly InternalLogDuplicatesPolicy DuplicatesPolicy;
+ private SdIdPolicySet sdIdPolicySet;
+
+ static SdId()
+ {
+ DuplicatesPolicy = new InternalLogDuplicatesPolicy();
+ }
+
+ public SdId() : this(string.Empty)
+ {
+ }
+
+ public SdId(string text) : base(text)
+ {
+ }
+
+ internal void Initialize(Enforcement enforcement)
+ {
+ sdIdPolicySet = new SdIdPolicySet(enforcement);
+ }
+
+ public static implicit operator SdId(string text)
+ {
+ return new SdId(text);
+ }
+
+ internal static IEnumerable> Bytes(IEnumerable sdIds, LogEventInfo logEvent, EncodingSet encodings)
+ {
+ return InternalLogDuplicatesPolicy.Apply(sdIds, x => x.Render(logEvent))
+ .Select(x => x.Bytes(logEvent, encodings));
+ }
+
+ private IEnumerable Bytes(LogEventInfo logEvent, EncodingSet encodings)
+ {
+ var sdId = sdIdPolicySet.Apply(Render(logEvent));
+ return encodings.Ascii.GetBytes(sdId);
+ }
+
+ public override string ToString()
+ {
+ var nullEvent = LogEventInfo.CreateNullEvent();
+ return Render(nullEvent);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageCreation/SdIdToInvalidParamNamePattern.cs b/src/NLog.Targets.Syslog/MessageCreation/SdIdToInvalidParamNamePattern.cs
new file mode 100644
index 00000000..9a0f6533
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageCreation/SdIdToInvalidParamNamePattern.cs
@@ -0,0 +1,38 @@
+using System.Collections.Generic;
+
+namespace NLog.Targets.Syslog.MessageCreation
+{
+ internal class SdIdToInvalidParamNamePattern
+ {
+ private const string Timequality = "timeQuality";
+ private const string Origin = "origin";
+ private const string Meta = "meta";
+ private static readonly string[] TimeQualityParamNames = { "tzKnown", "isSynced", "syncAccuracy" };
+ private static readonly string[] OriginParamNames = { "ip", "enterpriseId", "software", "swVersion" };
+ private static readonly string[] MetaParamNames = { "sequenceId", "sysUpTime", "language" };
+ private const string InvalidIanaParamName = @"^(?!^(?:{0})$).*$";
+ private static readonly Dictionary InvalidIanaParamNames = new Dictionary
+ {
+ { Timequality, BuildInvalidIanaParamNamePattern(TimeQualityParamNames) },
+ { Origin, BuildInvalidIanaParamNamePattern(OriginParamNames) },
+ { Meta, BuildInvalidIanaParamNamePattern(MetaParamNames) }
+ };
+ private const string NonSafePrintUsAscii = @"[^\u0022\u003D\u005D\u0020-\u007E]";
+ private const string InvalidCustomParamName = NonSafePrintUsAscii;
+
+ /// Maps an SD-ID to the corresponding invalid values for PARAM-NAME fields
+ /// The string representation of the SD-ID
+ /// The invalid PARAM-NAME pattern
+ public static string Map(string sdId)
+ {
+ return InvalidIanaParamNames.ContainsKey(sdId) ? InvalidIanaParamNames[sdId] : InvalidCustomParamName;
+ }
+
+ private static string BuildInvalidIanaParamNamePattern(params string[] args)
+ {
+ var joined = string.Join("|", args);
+ var formatted = string.Format(InvalidIanaParamName, joined);
+ return formatted;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageCreation/SdParam.cs b/src/NLog.Targets.Syslog/MessageCreation/SdParam.cs
new file mode 100644
index 00000000..3793385a
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageCreation/SdParam.cs
@@ -0,0 +1,68 @@
+using NLog.Config;
+using NLog.Layouts;
+using NLog.Targets.Syslog.Policies;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace NLog.Targets.Syslog.MessageCreation
+{
+ /// A Syslog SD-PARAM field
+ [NLogConfigurationItem]
+ public class SdParam
+ {
+ private ParamNamePolicySet paramNamePolicySet;
+ private ParamValuePolicySet paramValuePolicySet;
+ private static readonly byte[] SpaceBytes = { 0x20 };
+ private static readonly byte[] EqualBytes = { 0x3D };
+ private static readonly byte[] QuotesBytes = { 0x22 };
+
+ /// The PARAM-NAME field of this SD-PARAM
+ public Layout Name { get; set; }
+
+ /// The PARAM-VALUE field of this SD-PARAM
+ public Layout Value { get; set; }
+
+ internal void Initialize(Enforcement enforcement)
+ {
+ paramNamePolicySet = new ParamNamePolicySet(enforcement);
+ paramValuePolicySet = new ParamValuePolicySet(enforcement);
+ }
+
+ internal static string ToString(IEnumerable sdParams)
+ {
+ return sdParams.Aggregate(string.Empty, (acc, cur) => $"{acc} {cur.ToString()}");
+ }
+
+ public override string ToString()
+ {
+ var nullEvent = LogEventInfo.CreateNullEvent();
+ return $"{Name.Render(nullEvent)}=\"{Value.Render(nullEvent)}\"";
+ }
+
+ internal static IEnumerable Bytes(IEnumerable sdParams, LogEventInfo logEvent, string invalidNamesPattern, EncodingSet encodings)
+ {
+ return sdParams.SelectMany(sdParam => SpaceBytes.Concat(sdParam.Bytes(logEvent, invalidNamesPattern, encodings)));
+ }
+
+ private IEnumerable Bytes(LogEventInfo logEvent, string invalidNamesPattern, EncodingSet encodings)
+ {
+ return NameBytes(logEvent, invalidNamesPattern, encodings)
+ .Concat(EqualBytes)
+ .Concat(QuotesBytes)
+ .Concat(ValueBytes(logEvent, encodings))
+ .Concat(QuotesBytes);
+ }
+
+ private IEnumerable NameBytes(LogEventInfo logEvent, string invalidNamesPattern, EncodingSet encodings)
+ {
+ var paramName = paramNamePolicySet.Apply(Name.Render(logEvent), invalidNamesPattern);
+ return encodings.Ascii.GetBytes(paramName);
+ }
+
+ private IEnumerable ValueBytes(LogEventInfo logEvent, EncodingSet encodings)
+ {
+ var paramValue = paramValuePolicySet.Apply(Value.Render(logEvent));
+ return encodings.Utf8.GetBytes(paramValue);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageCreation/Severity.cs b/src/NLog.Targets.Syslog/MessageCreation/Severity.cs
new file mode 100644
index 00000000..5fecfaa0
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageCreation/Severity.cs
@@ -0,0 +1,46 @@
+using System.Collections.Generic;
+
+namespace NLog.Targets.Syslog.MessageCreation
+{
+ internal class Severity
+ {
+ private readonly int value;
+ private static readonly Severity Emergency = new Severity(0);
+ //private static readonly Severity Alert = new Severity(1);
+ //private static readonly Severity Critical = new Severity(2);
+ private static readonly Severity Error = new Severity(3);
+ private static readonly Severity Warning = new Severity(4);
+ private static readonly Severity Notice = new Severity(5);
+ private static readonly Severity Informational = new Severity(6);
+ private static readonly Severity Debug = new Severity(7);
+ private static readonly Dictionary LogLevelToSeverity;
+
+ static Severity()
+ {
+ LogLevelToSeverity = new Dictionary
+ {
+ { LogLevel.Fatal, Emergency },
+ { LogLevel.Error, Error },
+ { LogLevel.Warn, Warning },
+ { LogLevel.Info, Informational },
+ { LogLevel.Debug, Debug },
+ { LogLevel.Trace, Notice }
+ };
+ }
+
+ private Severity(int value)
+ {
+ this.value = value;
+ }
+
+ public static explicit operator int(Severity severity)
+ {
+ return severity.value;
+ }
+
+ public static explicit operator Severity(LogLevel logLevel)
+ {
+ return LogLevelToSeverity[logLevel];
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageCreation/StructuredData.cs b/src/NLog.Targets.Syslog/MessageCreation/StructuredData.cs
new file mode 100644
index 00000000..e3e34e6b
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageCreation/StructuredData.cs
@@ -0,0 +1,47 @@
+using NLog.Config;
+using NLog.Layouts;
+using NLog.Targets.Syslog.Policies;
+using System.Collections.Generic;
+
+namespace NLog.Targets.Syslog.MessageCreation
+{
+ /// A Syslog STRUCTURED-DATA part
+ [NLogConfigurationItem]
+ public class StructuredData
+ {
+ private const string NilValue = "-";
+ private static readonly byte[] NilValueBytes = { 0x2D };
+
+ public Layout FromEventProperties { get; set; }
+
+ /// The SD-ELEMENTs contained in the STRUCTURED-DATA part
+ [ArrayParameter(typeof(SdElement), nameof(SdElement))]
+ public IList SdElements { get; set; }
+
+ /// Builds a new instance of the StructuredData class
+ public StructuredData()
+ {
+ FromEventProperties = string.Empty;
+ SdElements = new List();
+ }
+
+ internal void Initialize(Enforcement enforcement)
+ {
+ SdElements.ForEach(sdElem => sdElem.Initialize(enforcement));
+ }
+
+ public override string ToString()
+ {
+ return SdElements.Count == 0 ? NilValue : SdElement.ToString(SdElements);
+ }
+
+ internal IEnumerable Bytes(LogEventInfo logEvent, EncodingSet encodings)
+ {
+ var sdFromEvtProps = FromEventProperties.Render(logEvent);
+ if (!string.IsNullOrEmpty(sdFromEvtProps))
+ return encodings.Utf8.GetBytes(sdFromEvtProps);
+
+ return SdElements.Count == 0 ? NilValueBytes : SdElement.Bytes(SdElements, logEvent, encodings);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageSend/FramingMethod.cs b/src/NLog.Targets.Syslog/MessageSend/FramingMethod.cs
new file mode 100644
index 00000000..54f7f810
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageSend/FramingMethod.cs
@@ -0,0 +1,9 @@
+namespace NLog.Targets.Syslog.MessageSend
+{
+ /// The framing method to be used when transmitting a message
+ public enum FramingMethod
+ {
+ NonTransparent,
+ OctetCounting
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageSend/MessageTransmitter.cs b/src/NLog.Targets.Syslog/MessageSend/MessageTransmitter.cs
new file mode 100644
index 00000000..215f8ec6
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageSend/MessageTransmitter.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+
+namespace NLog.Targets.Syslog.MessageSend
+{
+ public abstract class MessageTransmitter
+ {
+ private const string Localhost = "localhost";
+ private const int DefaultPort = 514;
+
+ /// The IP address of the Syslog server or an empty string
+ protected string IpAddress { get; private set; }
+
+ private string server;
+
+ /// The IP address or hostname of the Syslog server
+ public string Server
+ {
+ get { return server; }
+ set { server = value; IpAddress = Dns.GetHostAddresses(Server).FirstOrDefault()?.ToString(); }
+ }
+
+ /// The port number the Syslog server is listening on
+ public int Port { get; set; }
+
+ /// Builds the base part of a new instance of a class inheriting from MessageTransmitter
+ protected MessageTransmitter()
+ {
+ Server = Localhost;
+ Port = DefaultPort;
+ }
+
+ internal virtual IEnumerable FrameMessageOrLeaveItUnchanged(IEnumerable message)
+ {
+ return message;
+ }
+
+ internal abstract void SendMessages(IEnumerable messages);
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageSend/MessageTransmittersFacade.cs b/src/NLog.Targets.Syslog/MessageSend/MessageTransmittersFacade.cs
new file mode 100644
index 00000000..728fede3
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageSend/MessageTransmittersFacade.cs
@@ -0,0 +1,47 @@
+using System.Collections.Generic;
+
+namespace NLog.Targets.Syslog.MessageSend
+{
+ public class MessageTransmittersFacade
+ {
+ private MessageTransmitter activeTransmitter;
+ private readonly Dictionary transmitters;
+
+ /// The Syslog server protocol
+ public ProtocolType Protocol { get; set; }
+
+ /// UDP related fields
+ public UdpProtocol UdpProtocol { get; set; }
+
+ /// TCP related fields
+ public TcpProtocol TcpProtocol { get; set; }
+
+ /// Builds a new instance of the MessageTransmittersFacade class
+ public MessageTransmittersFacade()
+ {
+ Protocol = ProtocolType.Tcp;
+ UdpProtocol = new UdpProtocol();
+ TcpProtocol = new TcpProtocol();
+ transmitters = new Dictionary
+ {
+ {ProtocolType.Udp, UdpProtocol},
+ {ProtocolType.Tcp, TcpProtocol}
+ };
+ }
+
+ internal void Initialize()
+ {
+ activeTransmitter = transmitters[Protocol];
+ }
+
+ internal IEnumerable FrameMessageOrLeaveItUnchanged(IEnumerable message)
+ {
+ return activeTransmitter.FrameMessageOrLeaveItUnchanged(message);
+ }
+
+ internal void SendMessages(IEnumerable messages)
+ {
+ activeTransmitter.SendMessages(messages);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageSend/ProtocolType.cs b/src/NLog.Targets.Syslog/MessageSend/ProtocolType.cs
new file mode 100644
index 00000000..3db84fa8
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageSend/ProtocolType.cs
@@ -0,0 +1,9 @@
+namespace NLog.Targets.Syslog.MessageSend
+{
+ /// The protocol to be used when transmitting a message
+ public enum ProtocolType
+ {
+ Udp,
+ Tcp
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageSend/TcpProtocol.cs b/src/NLog.Targets.Syslog/MessageSend/TcpProtocol.cs
new file mode 100644
index 00000000..2aff15f7
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageSend/TcpProtocol.cs
@@ -0,0 +1,82 @@
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Security.Authentication;
+using System.Text;
+
+namespace NLog.Targets.Syslog.MessageSend
+{
+ [DisplayName("Tcp")]
+ public class TcpProtocol : MessageTransmitter
+ {
+ private FramingMethod framing;
+ private static readonly byte[] LineFeedBytes = { 0x0A };
+
+ /// Whether to use TLS or not (TLS 1.2 only)
+ public bool UseTls { get; set; }
+
+ /// Which framing method to use
+ /// If is true get will always return OctetCounting (RFC 5425)
+ public FramingMethod Framing
+ {
+ get { return UseTls ? FramingMethod.OctetCounting : framing; }
+ set { framing = value; }
+ }
+
+ /// Builds a new instance of the TcpProtocol class
+ public TcpProtocol()
+ {
+ UseTls = true;
+ Framing = FramingMethod.OctetCounting;
+ }
+
+ internal override IEnumerable FrameMessageOrLeaveItUnchanged(IEnumerable message)
+ {
+ return OctectCountingFramedOrUnchanged(NonTransparentFramedOrUnchanged(message));
+ }
+
+ internal override void SendMessages(IEnumerable messages)
+ {
+ if (string.IsNullOrEmpty(IpAddress))
+ return;
+
+ using (var tcp = new TcpClient(IpAddress, Port))
+ using (var stream = SslDecorate(tcp))
+ {
+ foreach (var message in messages)
+ stream.Write(message, 0, message.Length);
+ }
+ }
+
+ private IEnumerable OctectCountingFramedOrUnchanged(IEnumerable message)
+ {
+ if (Framing != FramingMethod.OctetCounting)
+ return message;
+
+ var messageAsArray = message.ToArray();
+ var octetCount = messageAsArray.Length;
+ var prefix = new ASCIIEncoding().GetBytes($"{octetCount} ");
+ return prefix.Concat(messageAsArray);
+ }
+
+ private IEnumerable NonTransparentFramedOrUnchanged(IEnumerable message)
+ {
+ return Framing != FramingMethod.NonTransparent ? message : message.Concat(LineFeedBytes);
+ }
+
+ private Stream SslDecorate(TcpClient tcp)
+ {
+ var tcpStream = tcp.GetStream();
+
+ if (!UseTls)
+ return tcpStream;
+
+ var sslStream = new SslStream(tcpStream, true);
+ sslStream.AuthenticateAsClient(Server, null, SslProtocols.Tls12, false);
+ return sslStream;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/MessageSend/UdpProtocol.cs b/src/NLog.Targets.Syslog/MessageSend/UdpProtocol.cs
new file mode 100644
index 00000000..653e8af0
--- /dev/null
+++ b/src/NLog.Targets.Syslog/MessageSend/UdpProtocol.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Net.Sockets;
+
+namespace NLog.Targets.Syslog.MessageSend
+{
+ [DisplayName("Udp")]
+ public class UdpProtocol : MessageTransmitter
+ {
+ internal override void SendMessages(IEnumerable messages)
+ {
+ if (string.IsNullOrEmpty(IpAddress))
+ return;
+
+ using (var udp = new UdpClient(IpAddress, Port))
+ {
+ foreach (var message in messages)
+ udp.Send(message, message.Length);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/NLog.Targets.Syslog.cs b/src/NLog.Targets.Syslog/NLog.Targets.Syslog.cs
deleted file mode 100644
index eef9ee78..00000000
--- a/src/NLog.Targets.Syslog/NLog.Targets.Syslog.cs
+++ /dev/null
@@ -1,287 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// NLog.Targets.Syslog
-// ------------------------------------------------------------------------
-// Copyright 2013 Jesper Hess Nielsen
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-////////////////////////////////////////////////////////////////////////////////
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Net;
-using System.Net.Security;
-using System.Net.Sockets;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Text;
-using NLog.Common;
-using NLog.Layouts;
-
-// ReSharper disable UnusedMember.Global
-// ReSharper disable MemberCanBePrivate.Global
-// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
-// ReSharper disable UnusedAutoPropertyAccessor.Global
-// ReSharper disable CheckNamespace
-namespace NLog.Targets
-// ReSharper restore CheckNamespace
-{
- /// This class enables logging to a unix-style syslog server using NLog
- [Target("Syslog")]
- public class Syslog : TargetWithLayout
- {
- private const string NilValue = "-";
- private static readonly CultureInfo _usCulture = new CultureInfo("en-US");
- private static readonly byte[] _bom = { 0xEF, 0xBB, 0xBF };
- private static readonly char[] _lineSeps = { '\r', '\n' };
-
- /// Gets or sets the IP Address or Host name of your Syslog server
- public string SyslogServer { get; set; }
-
- /// Gets or sets the port number syslog is running on (usually 514)
- public int Port { get; set; }
-
- /// Gets or sets the name of the application that will show up in the syslog log
- public Layout Sender { get; set; }
-
- /// Gets or sets the timestamp format
- public string TimestampFormat { get; set; }
-
- /// Gets or sets the machine name hosting syslog
- public Layout MachineName { get; set; }
-
- /// Gets or sets the syslog facility name to transmit message from (e.g. local0 or local7)
- public SyslogFacility Facility { get; set; }
-
- /// Gets or sets the syslog server protocol (TCP/UDP)
- public ProtocolType Protocol { get; set; }
-
- /// If this is set, try to configure and use SSL if available
- public bool Ssl { get; set; }
-
- /// If set, split message by newlines and send as separate messages
- public bool SplitNewlines { get; set; }
-
- /// RFC number for syslog protocol
- public RfcNumber Rfc { get; set; }
-
- #region RFC 5424 members
-
- /// Syslog protocol version for RFC 5424
- private byte ProtocolVersion { get; }
-
- /// Layout for PROCID protocol field
- public Layout ProcId { get; set; }
-
- /// Layout for MSGID protocol field
- public Layout MsgId { get; set; }
-
- /// Layout for STRUCTURED-DATA protocol field
- public Layout StructuredData { get; set; }
-
- #endregion
-
- /// Initializes a new instance of the Syslog class
- public Syslog()
- {
- SyslogServer = "127.0.0.1";
- Port = 514;
- Sender = Assembly.GetCallingAssembly().GetName().Name;
- Facility = SyslogFacility.Local1;
- Protocol = ProtocolType.Udp;
- TimestampFormat = "MMM dd HH:mm:ss";
- MachineName = Dns.GetHostName();
- SplitNewlines = true;
- Rfc = RfcNumber.Rfc3164;
-
- //Defaults for rfc 5424
- ProtocolVersion = 1;
- ProcId = NilValue;
- MsgId = NilValue;
- StructuredData = NilValue;
- }
-
- ///
- /// Writes single event.
- /// No need to override sync version of Write(LogEventInfo) because it is called only from async version.
- ///
- /// The NLog.AsyncLogEventInfo
- protected override void Write(AsyncLogEventInfo logEvent)
- {
- SendEventsBatch(logEvent);
- }
-
- /// Writes array of events
- /// The array of NLog.AsyncLogEventInfo
- protected override void Write(AsyncLogEventInfo[] logEvents)
- {
- SendEventsBatch(logEvents);
- }
-
- /// Sends array of events to syslog server
- /// The array of NLog.AsyncLogEventInfo
- private void SendEventsBatch(params AsyncLogEventInfo[] logEvents)
- {
- var logServerIp = Dns.GetHostAddresses(SyslogServer).FirstOrDefault();
- if (logServerIp == null)
- {
- return;
- }
- var ipAddress = logServerIp.ToString();
- switch (Protocol)
- {
- case ProtocolType.Udp:
- using (var udp = new UdpClient(ipAddress, Port))
- {
- ProcessAndSendEvents(logEvents, messageData => udp.Send(messageData, messageData.Length));
- }
- break;
- case ProtocolType.Tcp:
- using (var tcp = new TcpClient(ipAddress, Port))
- {
- // disposition of tcp also disposes stream
- var stream = tcp.GetStream();
- if (Ssl)
- {
- // leave stream open so that we don't double dispose
- using (var sslStream = new SslStream(stream, true))
- {
- sslStream.AuthenticateAsClient(SyslogServer);
- ProcessAndSendEvents(logEvents, messageData => sslStream.Write(messageData, 0, messageData.Length));
- }
- }
- else
- {
- ProcessAndSendEvents(logEvents, messageData => stream.Write(messageData, 0, messageData.Length));
- }
- }
- break;
- default:
- throw new NLogConfigurationException($"Protocol '{Protocol}' is not supported.");
- }
- }
-
- /// Processes array of events and sends messages bytes using action
- /// The array of NLog.AsyncLogEventInfo
- /// Implementation of send data method
- void ProcessAndSendEvents(AsyncLogEventInfo[] logEvents, Action messageSendAction)
- {
- foreach (var asyncLogEvent in logEvents)
- {
- var logEvent = asyncLogEvent.LogEvent;
- var formattedMessageLines = FormatMessageLines(logEvent);
- var severity = (SyslogSeverity)logEvent.Level;
- foreach (var formattedMessageLine in formattedMessageLines)
- {
- var message = BuildSyslogMessage(logEvent, Facility, severity, formattedMessageLine);
- messageSendAction(message);
- }
- }
- }
-
- /// Builds a syslog-compatible message using the information we have available
- /// The NLog.LogEventInfo
- /// Syslog Facility to transmit message from
- /// Syslog severity level
- /// Message text
- /// Byte array containing formatted syslog message
- private byte[] BuildSyslogMessage(LogEventInfo logEvent, SyslogFacility facility, SyslogSeverity priority, string body)
- {
- switch (Rfc)
- {
- case RfcNumber.Rfc5424:
- return BuildSyslogMessage5424(logEvent, facility, priority, body);
- default:
- return BuildSyslogMessage3164(logEvent, facility, priority, body);
- }
- }
-
- /// Builds rfc-3164 compatible message
- /// The NLog.LogEventInfo
- /// Syslog Facility to transmit message from
- /// Syslog severity level
- /// Message text
- /// Byte array containing formatted syslog message
- private byte[] BuildSyslogMessage3164(LogEventInfo logEvent, SyslogFacility facility, SyslogSeverity severity, string body)
- {
- // Calculate PRI field
- var priority = CalculatePriorityValue(facility, severity).ToString(CultureInfo.InvariantCulture);
- var time = logEvent.TimeStamp.ToLocalTime().ToString(TimestampFormat, _usCulture);
- // Get sender machine name
- var machine = MachineName.Render(logEvent);
- // Get sender
- var sender = Sender.Render(logEvent);
-
- return Encoding.ASCII.GetBytes($"<{priority}>{time} {machine} {sender}: {body}{Environment.NewLine}");
- }
-
- /// Builds rfc-5424 compatible message
- /// The NLog.LogEventInfo
- /// Syslog Facility to transmit message from
- /// Syslog severity level
- /// Message text
- /// Byte array containing formatted syslog message
- private byte[] BuildSyslogMessage5424(LogEventInfo logEvent, SyslogFacility facility, SyslogSeverity severity, string body)
- {
- // Calculate PRI field
- var priority = CalculatePriorityValue(facility, severity).ToString(CultureInfo.InvariantCulture);
- var version = ProtocolVersion.ToString(CultureInfo.InvariantCulture);
- var time = logEvent.TimeStamp.ToString("o");
- // Get sender machine name
- var machine = Left(MachineName.Render(logEvent), 255);
- var sender = Left(Sender.Render(logEvent), 48);
- var procId = Left(ProcId.Render(logEvent), 128);
- var msgId = Left(MsgId.Render(logEvent), 32);
-
- var headerData = Encoding.ASCII.GetBytes($"<{priority}>{version} {time} {machine} {sender} {procId} {msgId} ");
- var structuredData = Encoding.UTF8.GetBytes(StructuredData.Render(logEvent) + " ");
- var messageData = Encoding.UTF8.GetBytes(body);
-
- var allData = new List(headerData.Length + structuredData.Length + _bom.Length + messageData.Length);
- allData.AddRange(headerData);
- allData.AddRange(structuredData);
- allData.AddRange(_bom);
- allData.AddRange(messageData);
- return allData.ToArray();
- }
-
- /// Gets at most length first symbols
- /// Source string
- /// Maximum symbols count
- /// String that contains at most length symbols
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static string Left(string value, int length)
- {
- return value.Length <= length ? value : value.Substring(0, length);
- }
-
- /// Renders message lines
- /// The NLog.LogEventInfo
- private IEnumerable FormatMessageLines(LogEventInfo logEvent)
- {
- var msg = Layout.Render(logEvent);
- return SplitNewlines ? msg.Split(_lineSeps, StringSplitOptions.RemoveEmptyEntries) : new[] { msg };
- }
-
- /// Calculates syslog PRIVAL
- /// Syslog facility to transmit message from
- /// Syslog severity level
- /// Byte array containing formatted syslog message
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int CalculatePriorityValue(SyslogFacility facility, SyslogSeverity severity)
- {
- return (int)facility * 8 + (int)severity;
- }
- }
-}
\ No newline at end of file
diff --git a/src/NLog.Targets.Syslog/NLog.Targets.Syslog.csproj b/src/NLog.Targets.Syslog/NLog.Targets.Syslog.csproj
index 14e7640f..5a22f89e 100644
--- a/src/NLog.Targets.Syslog/NLog.Targets.Syslog.csproj
+++ b/src/NLog.Targets.Syslog/NLog.Targets.Syslog.csproj
@@ -43,23 +43,68 @@
- ..\packages\NLog.4.2.2\lib\net45\NLog.dll
+ ..\packages\NLog.4.3.3\lib\net45\NLog.dll
True
-
+
+ ..\packages\UnidecodeSharpFork.1.0.0\lib\UnidecodeSharpFork.dll
+ True
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:sl="https://github.com/graffen/NLog.Targets.Syslog/tree/master/src/schemas/NLog.Targets.Syslog.xsd">
+
+
+
+
+
+ utf-8
+ true
+
+ ${basedir}/log.txt
+
+
+
+
+
+ true
+ true
+ true
+ true
+ 1024
+
+
+ Local4
+ Rfc3164
+
+
+
+ TCP
+
+ 127.0.0.1
+ 1514
+
+
+ 127.0.0.1
+ 1514
+ false
+ octetCounting
+
+
+
+
+
+
+ false
+ false
+ false
+ true
+ 1024
+
+
+ Local4
+ Rfc5424
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UDP
+
+ 127.0.0.1
+ 1514
+
+
+ 127.0.0.1
+ 1514
+ false
+ nonTransparent
+
+
+
+
+
+
+ false
+ false
+ false
+ true
+ 1024
+
+
+ Local4
+ Rfc5424
+
+
+
+
+
+
+ true
+
+
+
+ UDP
+
+ 127.0.0.1
+ 1514
+
+
+ 127.0.0.1
+ 1514
+ false
+ octetCounting
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/TestApp/NLog.xsd b/src/TestApp/NLog.xsd
new file mode 100644
index 00000000..dc821bc0
--- /dev/null
+++ b/src/TestApp/NLog.xsd
@@ -0,0 +1,2601 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Watch config file for changes and reload automatically.
+
+
+
+
+ Print internal NLog messages to the console. Default value is: false
+
+
+
+
+ Print internal NLog messages to the console error output. Default value is: false
+
+
+
+
+ Write internal NLog messages to the specified file.
+
+
+
+
+ Log level threshold for internal log messages. Default value is: Info.
+
+
+
+
+ Global log level threshold for application log messages. Messages below this level won't be logged..
+
+
+
+
+ Pass NLog internal exceptions to the application. Default value is: false.
+
+
+
+
+ Write internal NLog messages to the the System.Diagnostics.Trace. Default value is: false
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Prefix for targets/layout renderers/filters/conditions loaded from this assembly.
+
+
+
+
+ Load NLog extensions from the specified file (*.dll)
+
+
+
+
+ Load NLog extensions from the specified assembly. Assembly name should be fully qualified.
+
+
+
+
+
+
+
+
+
+ Name of the logger. May include '*' character which acts like a wildcard. Allowed forms are: *, Name, *Name, Name* and *Name*
+
+
+
+
+ Comma separated list of levels that this rule matches.
+
+
+
+
+ Minimum level that this rule matches.
+
+
+
+
+ Maximum level that this rule matches.
+
+
+
+
+ Level that this rule matches.
+
+
+
+
+ Comma separated list of target names.
+
+
+
+
+ Ignore further rules if this one matches.
+
+
+
+
+ Enable or disable logging rule. Disabled rules are ignored.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the file to be included. The name is relative to the name of the current config file.
+
+
+
+
+ Ignore any errors in the include file.
+
+
+
+
+
+
+ Variable name.
+
+
+
+
+ Variable value.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Layout used to format log messages.
+
+
+
+
+ Indicates whether to add <!-- --> comments around all written texts.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Number of log events that should be processed in a batch by the lazy writer thread.
+
+
+
+
+ Action to be taken when the lazy writer thread request queue count exceeds the set limit.
+
+
+
+
+ Limit on the number of requests in the lazy writer thread request queue.
+
+
+
+
+ Time in milliseconds to sleep between batches.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Number of log events to be buffered.
+
+
+
+
+ Timeout (in milliseconds) after which the contents of buffer will be flushed if there's no write in the specified period of time. Use -1 to disable timed flushes.
+
+
+
+
+ Indicates whether to use sliding timeout.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Encoding to be used.
+
+
+
+
+ Instance of that is used to format log messages.
+
+
+
+
+ Maximum message size in bytes.
+
+
+
+
+ Indicates whether to append newline at the end of log message.
+
+
+
+
+ Action that should be taken if the will be more connections than .
+
+
+
+
+ Action that should be taken if the message is larger than maxMessageSize.
+
+
+
+
+ Indicates whether to keep connection open whenever possible.
+
+
+
+
+ Size of the connection cache (number of connections which are kept alive).
+
+
+
+
+ Maximum current connections. 0 = no maximum.
+
+
+
+
+ Network address.
+
+
+
+
+ Maximum queue size.
+
+
+
+
+ Indicates whether to include source info (file name and line number) in the information sent over the network.
+
+
+
+
+ NDC item separator.
+
+
+
+
+ Indicates whether to include stack contents.
+
+
+
+
+ Indicates whether to include call site (class and method name) in the information sent over the network.
+
+
+
+
+ AppInfo field. By default it's the friendly name of the current AppDomain.
+
+
+
+
+ Indicates whether to include NLog-specific extensions to log4j schema.
+
+
+
+
+ Indicates whether to include dictionary contents.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Layout that should be use to calcuate the value for the parameter.
+
+
+
+
+ Viewer parameter name.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Text to be rendered.
+
+
+
+
+ Header.
+
+
+
+
+ Footer.
+
+
+
+
+ Indicates whether to use default row highlighting rules.
+
+
+
+
+ The encoding for writing messages to the .
+
+
+
+
+ Indicates whether the error stream (stderr) should be used instead of the output stream (stdout).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Condition that must be met in order to set the specified foreground and background color.
+
+
+
+
+ Background color.
+
+
+
+
+ Foreground color.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Indicates whether to ignore case when comparing texts.
+
+
+
+
+ Regular expression to be matched. You must specify either text or regex.
+
+
+
+
+ Text to be matched. You must specify either text or regex.
+
+
+
+
+ Indicates whether to match whole words only.
+
+
+
+
+ Compile the ? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used.
+
+
+
+
+ Background color.
+
+
+
+
+ Foreground color.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Text to be rendered.
+
+
+
+
+ Header.
+
+
+
+
+ Footer.
+
+
+
+
+ Indicates whether to send the log messages to the standard error instead of the standard output.
+
+
+
+
+ The encoding for writing messages to the .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Connection string. When provided, it overrides the values specified in DBHost, DBUserName, DBPassword, DBDatabase.
+
+
+
+
+ Name of the connection string (as specified in <connectionStrings> configuration section.
+
+
+
+
+ Database name. If the ConnectionString is not provided this value will be used to construct the "Database=" part of the connection string.
+
+
+
+
+ Database host name. If the ConnectionString is not provided this value will be used to construct the "Server=" part of the connection string.
+
+
+
+
+ Database password. If the ConnectionString is not provided this value will be used to construct the "Password=" part of the connection string.
+
+
+
+
+ Name of the database provider.
+
+
+
+
+ Database user name. If the ConnectionString is not provided this value will be used to construct the "User ID=" part of the connection string.
+
+
+
+
+ Indicates whether to keep the database connection open between the log events.
+
+
+
+
+ Obsolete - value will be ignored! The logging code always runs outside of transaction. Gets or sets a value indicating whether to use database transactions. Some data providers require this.
+
+
+
+
+ Connection string using for installation and uninstallation. If not provided, regular ConnectionString is being used.
+
+
+
+
+ Text of the SQL command to be run on each log level.
+
+
+
+
+ Type of the SQL command to be run on each log level.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Type of the command.
+
+
+
+
+ Connection string to run the command against. If not provided, connection string from the target is used.
+
+
+
+
+ Indicates whether to ignore failures.
+
+
+
+
+ Command text.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Layout that should be use to calcuate the value for the parameter.
+
+
+
+
+ Database parameter name.
+
+
+
+
+ Database parameter precision.
+
+
+
+
+ Database parameter scale.
+
+
+
+
+ Database parameter size.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Text to be rendered.
+
+
+
+
+ Header.
+
+
+
+
+ Footer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Layout used to format log messages.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Layout used to format log messages.
+
+
+
+
+ Layout that renders event Category.
+
+
+
+
+ Layout that renders event ID.
+
+
+
+
+ Name of the Event Log to write to. This can be System, Application or any user-defined name.
+
+
+
+
+ Name of the machine on which Event Log service is running.
+
+
+
+
+ Value to be used as the event Source.
+
+
+
+
+ Action to take if the message is larger than the option.
+
+
+
+
+ Optional entrytype. When not set, or when not convertable to then determined by
+
+
+
+
+ Message length limit to write to the Event Log.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Indicates whether to return to the first target after any successful write.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Text to be rendered.
+
+
+
+
+ Header.
+
+
+
+
+ Footer.
+
+
+
+
+ File encoding.
+
+
+
+
+ Line ending mode.
+
+
+
+
+ Way file archives are numbered.
+
+
+
+
+ Name of the file to be used for an archive.
+
+
+
+
+ Indicates whether to automatically archive log files every time the specified time passes.
+
+
+
+
+ Size in bytes above which log files will be automatically archived. Warning: combining this with isn't supported. We cannot create multiple archive files, if they should have the same name. Choose:
+
+
+
+
+ Maximum number of archive files that should be kept.
+
+
+
+
+ Indicates whether to compress archive files into the zip archive format.
+
+
+
+
+ Gets or set a value indicating whether a managed file stream is forced, instead of used the native implementation.
+
+
+
+
+ Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong.
+
+
+
+
+ Name of the file to write to.
+
+
+
+
+ Value specifying the date format to use when archiving files.
+
+
+
+
+ Indicates whether to archive old log file on startup.
+
+
+
+
+ Indicates whether to create directories if they do not exist.
+
+
+
+
+ Indicates whether to enable log file(s) to be deleted.
+
+
+
+
+ File attributes (Windows only).
+
+
+
+
+ Indicates whether to delete old log file on startup.
+
+
+
+
+ Indicates whether to replace file contents on each write instead of appending log message at the end.
+
+
+
+
+ Indicates whether concurrent writes to the log file by multiple processes on the same host.
+
+
+
+
+ Delay in milliseconds to wait before attempting to write to the file again.
+
+
+
+
+ Maximum number of log filenames that should be stored as existing.
+
+
+
+
+ Indicates whether concurrent writes to the log file by multiple processes on different network hosts.
+
+
+
+
+ Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger).
+
+
+
+
+ Maximum number of seconds that files are kept open. If this number is negative the files are not automatically closed after a period of inactivity.
+
+
+
+
+ Log file buffer size in bytes.
+
+
+
+
+ Indicates whether to automatically flush the file buffers after each log message.
+
+
+
+
+ Number of times the write is appended on the file before NLog discards the log message.
+
+
+
+
+ Indicates whether to keep log file open instead of opening and closing it on each logging event.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Condition expression. Log events who meet this condition will be forwarded to the wrapped target.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Windows domain name to change context to.
+
+
+
+
+ Required impersonation level.
+
+
+
+
+ Type of the logon provider.
+
+
+
+
+ Logon Type.
+
+
+
+
+ User account password.
+
+
+
+
+ Indicates whether to revert to the credentials of the process instead of impersonating another user.
+
+
+
+
+ Username to change context to.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Endpoint address.
+
+
+
+
+ Name of the endpoint configuration in WCF configuration file.
+
+
+
+
+ Indicates whether to use a WCF service contract that is one way (fire and forget) or two way (request-reply)
+
+
+
+
+ Client ID.
+
+
+
+
+ Indicates whether to include per-event properties in the payload sent to the server.
+
+
+
+
+ Indicates whether to use binary message encoding.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Layout that should be use to calculate the value for the parameter.
+
+
+
+
+ Name of the parameter.
+
+
+
+
+ Type of the parameter.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Text to be rendered.
+
+
+
+
+ Header.
+
+
+
+
+ Footer.
+
+
+
+
+ Indicates whether to send message as HTML instead of plain text.
+
+
+
+
+ Encoding to be used for sending e-mail.
+
+
+
+
+ Indicates whether to add new lines between log entries.
+
+
+
+
+ CC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com).
+
+
+
+
+ Recipients' email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com).
+
+
+
+
+ BCC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com).
+
+
+
+
+ Mail message body (repeated for each log message send in one mail).
+
+
+
+
+ Mail subject.
+
+
+
+
+ Sender's email address (e.g. joe@domain.com).
+
+
+
+
+ Indicates whether NewLine characters in the body should be replaced with tags.
+
+
+
+
+ Priority used for sending mails.
+
+
+
+
+ Indicates the SMTP client timeout.
+
+
+
+
+ SMTP Server to be used for sending.
+
+
+
+
+ SMTP Authentication mode.
+
+
+
+
+ Username used to connect to SMTP server (used when SmtpAuthentication is set to "basic").
+
+
+
+
+ Password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic").
+
+
+
+
+ Indicates whether SSL (secure sockets layer) should be used when communicating with SMTP server.
+
+
+
+
+ Port number that SMTP Server is listening on.
+
+
+
+
+ Indicates whether the default Settings from System.Net.MailSettings should be used.
+
+
+
+
+ Folder where applications save mail messages to be processed by the local SMTP server.
+
+
+
+
+ Specifies how outgoing email messages will be handled.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Layout used to format log messages.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Layout used to format log messages.
+
+
+
+
+ Encoding to be used when writing text to the queue.
+
+
+
+
+ Indicates whether to use the XML format when serializing message. This will also disable creating queues.
+
+
+
+
+ Indicates whether to check if a queue exists before writing to it.
+
+
+
+
+ Indicates whether to create the queue if it doesn't exists.
+
+
+
+
+ Label to associate with each message.
+
+
+
+
+ Name of the queue to write to.
+
+
+
+
+ Indicates whether to use recoverable messages (with guaranteed delivery).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Class name.
+
+
+
+
+ Method name. The method must be public and static. Use the AssemblyQualifiedName , https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx e.g.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Layout used to format log messages.
+
+
+
+
+ Encoding to be used.
+
+
+
+
+ Maximum message size in bytes.
+
+
+
+
+ Indicates whether to append newline at the end of log message.
+
+
+
+
+ Action that should be taken if the will be more connections than .
+
+
+
+
+ Action that should be taken if the message is larger than maxMessageSize.
+
+
+
+
+ Network address.
+
+
+
+
+ Size of the connection cache (number of connections which are kept alive).
+
+
+
+
+ Indicates whether to keep connection open whenever possible.
+
+
+
+
+ Maximum current connections. 0 = no maximum.
+
+
+
+
+ Maximum queue size.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Encoding to be used.
+
+
+
+
+ Instance of that is used to format log messages.
+
+
+
+
+ Maximum message size in bytes.
+
+
+
+
+ Indicates whether to append newline at the end of log message.
+
+
+
+
+ Action that should be taken if the will be more connections than .
+
+
+
+
+ Action that should be taken if the message is larger than maxMessageSize.
+
+
+
+
+ Indicates whether to keep connection open whenever possible.
+
+
+
+
+ Size of the connection cache (number of connections which are kept alive).
+
+
+
+
+ Maximum current connections. 0 = no maximum.
+
+
+
+
+ Network address.
+
+
+
+
+ Maximum queue size.
+
+
+
+
+ Indicates whether to include source info (file name and line number) in the information sent over the network.
+
+
+
+
+ NDC item separator.
+
+
+
+
+ Indicates whether to include stack contents.
+
+
+
+
+ Indicates whether to include call site (class and method name) in the information sent over the network.
+
+
+
+
+ AppInfo field. By default it's the friendly name of the current AppDomain.
+
+
+
+
+ Indicates whether to include NLog-specific extensions to log4j schema.
+
+
+
+
+ Indicates whether to include dictionary contents.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Layout used to format log messages.
+
+
+
+
+ Indicates whether to perform layout calculation.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Layout used to format log messages.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Indicates whether performance counter should be automatically created.
+
+
+
+
+ Name of the performance counter category.
+
+
+
+
+ Counter help text.
+
+
+
+
+ Name of the performance counter.
+
+
+
+
+ Performance counter type.
+
+
+
+
+ The value by which to increment the counter.
+
+
+
+
+ Performance counter instance name.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Default filter to be applied when no specific rule matches.
+
+
+
+
+
+
+
+
+
+
+
+
+ Condition to be tested.
+
+
+
+
+ Resulting filter to be applied when the condition matches.
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Number of times to repeat each log message.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Number of retries that should be attempted on the wrapped target in case of a failure.
+
+
+
+
+ Time to wait between retries in milliseconds.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Layout used to format log messages.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name of the target.
+
+
+
+
+ Should we include the BOM (Byte-order-mark) for UTF? Influences the property. This will only work for UTF-8.
+
+
+
+
+ Encoding.
+
+
+
+
+ Web service method name. Only used with Soap.
+
+
+
+
+ Web service namespace. Only used with Soap.
+
+
+
+
+ Protocol to be used when calling web service.
+
+
+
+
+ Web service URL.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Footer layout.
+
+
+
+
+ Header layout.
+
+
+
+
+ Body layout (can be repeated multiple times).
+
+
+
+
+ Custom column delimiter value (valid when ColumnDelimiter is set to 'Custom').
+
+
+
+
+ Column delimiter.
+
+
+
+
+ Quote Character.
+
+
+
+
+ Quoting mode.
+
+
+
+
+ Indicates whether CVS should include header.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Layout of the column.
+
+
+
+
+ Name of the column.
+
+
+
+
+
+
+
+
+
+
+
+
+ Option to suppress the extra spaces in the output json
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Determines wether or not this attribute will be Json encoded.
+
+
+
+
+ Layout that will be rendered as the attribute's value.
+
+
+
+
+ Name of the attribute.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Footer layout.
+
+
+
+
+ Header layout.
+
+
+
+
+ Body layout (can be repeated multiple times).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Layout text.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Action to be taken when filter matches.
+
+
+
+
+ Condition expression.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Action to be taken when filter matches.
+
+
+
+
+ Indicates whether to ignore case when comparing strings.
+
+
+
+
+ Layout to be used to filter log messages.
+
+
+
+
+ Substring to be matched.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Action to be taken when filter matches.
+
+
+
+
+ String to compare the layout to.
+
+
+
+
+ Indicates whether to ignore case when comparing strings.
+
+
+
+
+ Layout to be used to filter log messages.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Action to be taken when filter matches.
+
+
+
+
+ Indicates whether to ignore case when comparing strings.
+
+
+
+
+ Layout to be used to filter log messages.
+
+
+
+
+ Substring to be matched.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Action to be taken when filter matches.
+
+
+
+
+ String to compare the layout to.
+
+
+
+
+ Indicates whether to ignore case when comparing strings.
+
+
+
+
+ Layout to be used to filter log messages.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/TestApp/Program.cs b/src/TestApp/Program.cs
index bd23040c..e196f60b 100644
--- a/src/TestApp/Program.cs
+++ b/src/TestApp/Program.cs
@@ -5,15 +5,12 @@ namespace TestApp
{
public static class Program
{
- ///
- /// The main entry point for the application.
- ///
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
- Application.Run(new Form1());
+ Application.Run(new FormTest());
}
}
}
\ No newline at end of file
diff --git a/src/TestApp/TestApp.csproj b/src/TestApp/TestApp.csproj
index 34b44349..66ac93e4 100644
--- a/src/TestApp/TestApp.csproj
+++ b/src/TestApp/TestApp.csproj
@@ -17,8 +17,8 @@
..\
true
-
- x86
+
+ AnyCPU
true
full
false
@@ -26,44 +26,36 @@
DEBUG;TRACE
prompt
4
- false
-
- x86
+
+ AnyCPU
pdbonly
true
bin\Release\
TRACE
prompt
4
- false
- ..\packages\NLog.4.2.2\lib\net45\NLog.dll
+ ..\packages\NLog.4.3.3\lib\net45\NLog.dll
True
-
-
-
-
-
-
-
+
Form
-
- Form1.cs
+
+ FormTest.cs
-
- Form1.cs
+
+ FormTest.cs
ResXFileCodeGenerator
@@ -80,7 +72,12 @@
Always
Designer
-
+
+ Designer
+
+
+ Designer
+
SettingsSingleFileGenerator
Settings.Designer.cs
diff --git a/src/TestApp/app.config b/src/TestApp/app.config
index 51278a45..17291947 100644
--- a/src/TestApp/app.config
+++ b/src/TestApp/app.config
@@ -1,3 +1,6 @@
-
+
+
+
+
diff --git a/src/TestApp/packages.config b/src/TestApp/packages.config
index d58c5f7c..32468a73 100644
--- a/src/TestApp/packages.config
+++ b/src/TestApp/packages.config
@@ -1,4 +1,5 @@
-
+
+
\ No newline at end of file
diff --git a/src/schemas/NLog.Targets.Syslog.xsd b/src/schemas/NLog.Targets.Syslog.xsd
new file mode 100644
index 00000000..839ae81c
--- /dev/null
+++ b/src/schemas/NLog.Targets.Syslog.xsd
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file