#region Apache License // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to you 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. // #endregion using System; using System.Globalization; using System.Net; using System.Net.Sockets; using System.Text; using log4net.Core; namespace log4net.Appender { /// /// Sends logging events as connectionless UDP datagrams to a remote host or a /// multicast group using an . /// /// /// /// UDP guarantees neither that messages arrive, nor that they arrive in the correct order. /// /// /// To view the logging results, a custom application can be developed that listens for logging /// events. /// /// /// When decoding events send via this appender remember to use the same encoding /// to decode the events as was used to send the events. See the /// property to specify the encoding to use. /// /// /// /// This example shows how to log receive logging events that are sent /// on IP address 244.0.0.1 and port 8080 to the console. The event is /// encoded in the packet as a unicode string and it is decoded as such. /// /// IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); /// UdpClient udpClient; /// byte[] buffer; /// string loggingEvent; /// /// try /// { /// udpClient = new UdpClient(8080); /// /// while(true) /// { /// buffer = udpClient.Receive(ref remoteEndPoint); /// loggingEvent = System.Text.Encoding.Unicode.GetString(buffer); /// Console.WriteLine(loggingEvent); /// } /// } /// catch(Exception e) /// { /// Console.WriteLine(e.ToString()); /// } /// /// /// Dim remoteEndPoint as IPEndPoint /// Dim udpClient as UdpClient /// Dim buffer as Byte() /// Dim loggingEvent as String /// /// Try /// remoteEndPoint = new IPEndPoint(IPAddress.Any, 0) /// udpClient = new UdpClient(8080) /// /// While True /// buffer = udpClient.Receive(ByRef remoteEndPoint) /// loggingEvent = System.Text.Encoding.Unicode.GetString(buffer) /// Console.WriteLine(loggingEvent) /// Wend /// Catch e As Exception /// Console.WriteLine(e.ToString()) /// End Try /// /// /// An example configuration section to log information using this appender to the /// IP 224.0.0.1 on port 8080: /// /// /// /// /// /// /// /// /// /// Gert Driesen /// Nicko Cadell public class UdpAppender : AppenderSkeleton { #region Public Instance Constructors /// /// Initializes a new instance of the class. /// /// /// The default constructor initializes all fields to their default values. /// public UdpAppender() { } #endregion Public Instance Constructors #region Public Instance Properties /// /// Gets or sets the IP address of the remote host or multicast group to which /// the underlying should sent the logging event. /// /// /// The IP address of the remote host or multicast group to which the logging event /// will be sent. /// /// /// /// Multicast addresses are identified by IP class D addresses (in the range 224.0.0.0 to /// 239.255.255.255). Multicast packets can pass across different networks through routers, so /// it is possible to use multicasts in an Internet scenario as long as your network provider /// supports multicasting. /// /// /// Hosts that want to receive particular multicast messages must register their interest by joining /// the multicast group. Multicast messages are not sent to networks where no host has joined /// the multicast group. Class D IP addresses are used for multicast groups, to differentiate /// them from normal host addresses, allowing nodes to easily detect if a message is of interest. /// /// /// Static multicast addresses that are needed globally are assigned by IANA. A few examples are listed in the table below: /// /// /// /// /// IP Address /// Description /// /// /// 224.0.0.1 /// /// /// Sends a message to all system on the subnet. /// /// /// /// /// 224.0.0.2 /// /// /// Sends a message to all routers on the subnet. /// /// /// /// /// 224.0.0.12 /// /// /// The DHCP server answers messages on the IP address 224.0.0.12, but only on a subnet. /// /// /// /// /// /// /// A complete list of actually reserved multicast addresses and their owners in the ranges /// defined by RFC 3171 can be found at the IANA web site. /// /// /// The address range 239.0.0.0 to 239.255.255.255 is reserved for administrative scope-relative /// addresses. These addresses can be reused with other local groups. Routers are typically /// configured with filters to prevent multicast traffic in this range from flowing outside /// of the local network. /// /// public IPAddress RemoteAddress { get { return m_remoteAddress; } set { m_remoteAddress = value; } } /// /// Gets or sets the TCP port number of the remote host or multicast group to which /// the underlying should sent the logging event. /// /// /// An integer value in the range to /// indicating the TCP port number of the remote host or multicast group to which the logging event /// will be sent. /// /// /// The underlying will send messages to this TCP port number /// on the remote host or multicast group. /// /// The value specified is less than or greater than . public int RemotePort { get { return m_remotePort; } set { if (value < IPEndPoint.MinPort || value > IPEndPoint.MaxPort) { throw log4net.Util.SystemInfo.CreateArgumentOutOfRangeException("value", (object)value, "The value specified is less than " + IPEndPoint.MinPort.ToString(NumberFormatInfo.InvariantInfo) + " or greater than " + IPEndPoint.MaxPort.ToString(NumberFormatInfo.InvariantInfo) + "."); } else { m_remotePort = value; } } } /// /// Gets or sets the TCP port number from which the underlying will communicate. /// /// /// An integer value in the range to /// indicating the TCP port number from which the underlying will communicate. /// /// /// /// The underlying will bind to this port for sending messages. /// /// /// Setting the value to 0 (the default) will cause the udp client not to bind to /// a local port. /// /// /// The value specified is less than or greater than . public int LocalPort { get { return m_localPort; } set { if (value != 0 && (value < IPEndPoint.MinPort || value > IPEndPoint.MaxPort)) { throw log4net.Util.SystemInfo.CreateArgumentOutOfRangeException("value", (object)value, "The value specified is less than " + IPEndPoint.MinPort.ToString(NumberFormatInfo.InvariantInfo) + " or greater than " + IPEndPoint.MaxPort.ToString(NumberFormatInfo.InvariantInfo) + "."); } else { m_localPort = value; } } } /// /// Gets or sets used to write the packets. /// /// /// The used to write the packets. /// /// /// /// The used to write the packets. /// /// public Encoding Encoding { get { return m_encoding; } set { m_encoding = value; } } #endregion Public Instance Properties #region Protected Instance Properties /// /// Gets or sets the underlying . /// /// /// The underlying . /// /// /// creates a to send logging events /// over a network. Classes deriving from can use this /// property to get or set this . Use the underlying /// returned from if you require access beyond that which /// provides. /// protected UdpClient Client { get { return this.m_client; } set { this.m_client = value; } } /// /// Gets or sets the cached remote endpoint to which the logging events should be sent. /// /// /// The cached remote endpoint to which the logging events will be sent. /// /// /// The method will initialize the remote endpoint /// with the values of the and /// properties. /// protected IPEndPoint RemoteEndPoint { get { return this.m_remoteEndPoint; } set { this.m_remoteEndPoint = value; } } #endregion Protected Instance Properties #region Implementation of IOptionHandler /// /// Initialize the appender based on the options set. /// /// /// /// This is part of the delayed object /// activation scheme. The method must /// be called on this object after the configuration properties have /// been set. Until is called this /// object is in an undefined state and must not be used. /// /// /// If any of the configuration properties are modified then /// must be called again. /// /// /// The appender will be ignored if no was specified or /// an invalid remote or local TCP port number was specified. /// /// /// The required property was not specified. /// The TCP port number assigned to or is less than or greater than . public override void ActivateOptions() { base.ActivateOptions(); if (this.RemoteAddress == null) { throw new ArgumentNullException("The required property 'Address' was not specified."); } else if (this.RemotePort < IPEndPoint.MinPort || this.RemotePort > IPEndPoint.MaxPort) { throw log4net.Util.SystemInfo.CreateArgumentOutOfRangeException("this.RemotePort", (object)this.RemotePort, "The RemotePort is less than " + IPEndPoint.MinPort.ToString(NumberFormatInfo.InvariantInfo) + " or greater than " + IPEndPoint.MaxPort.ToString(NumberFormatInfo.InvariantInfo) + "."); } else if (this.LocalPort != 0 && (this.LocalPort < IPEndPoint.MinPort || this.LocalPort > IPEndPoint.MaxPort)) { throw log4net.Util.SystemInfo.CreateArgumentOutOfRangeException("this.LocalPort", (object)this.LocalPort, "The LocalPort is less than " + IPEndPoint.MinPort.ToString(NumberFormatInfo.InvariantInfo) + " or greater than " + IPEndPoint.MaxPort.ToString(NumberFormatInfo.InvariantInfo) + "."); } else { this.RemoteEndPoint = new IPEndPoint(this.RemoteAddress, this.RemotePort); this.InitializeClientConnection(); } } #endregion #region Override implementation of AppenderSkeleton /// /// This method is called by the method. /// /// The event to log. /// /// /// Sends the event using an UDP datagram. /// /// /// Exceptions are passed to the . /// /// protected override void Append(LoggingEvent loggingEvent) { try { Byte [] buffer = m_encoding.GetBytes(RenderLoggingEvent(loggingEvent).ToCharArray()); #if NETSTANDARD Client.SendAsync(buffer, buffer.Length, RemoteEndPoint).Wait(); #else this.Client.Send(buffer, buffer.Length, this.RemoteEndPoint); #endif } catch (Exception ex) { ErrorHandler.Error( "Unable to send logging event to remote host " + this.RemoteAddress.ToString() + " on port " + this.RemotePort + ".", ex, ErrorCode.WriteFailure); } } /// /// This appender requires a to be set. /// /// true /// /// /// This appender requires a to be set. /// /// protected override bool RequiresLayout { get { return true; } } /// /// Closes the UDP connection and releases all resources associated with /// this instance. /// /// /// /// Disables the underlying and releases all managed /// and unmanaged resources associated with the . /// /// protected override void OnClose() { base.OnClose(); if (this.Client != null) { this.Client.Close(); } } #endregion Override implementation of AppenderSkeleton #region Protected Instance Methods /// /// Initializes the underlying connection. /// /// /// /// The underlying is initialized and binds to the /// port number from which you intend to communicate. /// /// /// Exceptions are passed to the . /// /// protected virtual void InitializeClientConnection() { try { if (this.LocalPort == 0) { #if NETCF || NET_1_0 || SSCLI_1_0 || CLI_1_0 this.Client = new UdpClient(); #else this.Client = new UdpClient(RemoteAddress.AddressFamily); #endif } else { #if NETCF || NET_1_0 || SSCLI_1_0 || CLI_1_0 this.Client = new UdpClient(this.LocalPort); #else this.Client = new UdpClient(this.LocalPort, RemoteAddress.AddressFamily); #endif } } catch (Exception ex) { ErrorHandler.Error( "Could not initialize the UdpClient connection on port " + this.LocalPort.ToString(NumberFormatInfo.InvariantInfo) + ".", ex, ErrorCode.GenericFailure); this.Client = null; } } #endregion Protected Instance Methods #region Private Instance Fields /// /// The IP address of the remote host or multicast group to which /// the logging event will be sent. /// private IPAddress m_remoteAddress; /// /// The TCP port number of the remote host or multicast group to /// which the logging event will be sent. /// private int m_remotePort; /// /// The cached remote endpoint to which the logging events will be sent. /// private IPEndPoint m_remoteEndPoint; /// /// The TCP port number from which the will communicate. /// private int m_localPort; /// /// The instance that will be used for sending the /// logging events. /// private UdpClient m_client; /// /// The encoding to use for the packet. /// #if NETSTANDARD private Encoding m_encoding = Encoding.Unicode; #else private Encoding m_encoding = Encoding.Default; #endif #endregion Private Instance Fields } }