ELK集成Log4net 重写一个TcpAppender

 最近搞了下ELK,三个工具部署完毕,想再集成上log4net。没想到.net core版Log4net竟然没有直接Tcp发送消息的appender。醉了。log4net

1.RemotingAppender:core已经不支持。

2.RemoteSysLogAppender:只监听 udp的514端口。【原文:The BSD syslog protocol is used to remotely log to a syslog daemon. The syslogd listens for for messages on UDP port 514.】

3.UdpAppender:udp协议传输数据

4.TelnetAppender:一开始以为肯定是这个可以用了。官网没有examples。。科学上网翻了config。里面竟然只有port配置没有remotingAddress等(黑人问号)???。官网解释这个东西怎么玩的【原文:The TelnetAppender accepts socket connections and streams logging messages back to the client. The output is provided in a telnet-friendly way so that a log can be monitored over a TCP/IP socket. This allows simple remote monitoring of application logging.】

也就是它是开了一个监听。监听别人给他发的日志数据,然后记录数据然后再发回去。。。What???。我要的是你发出去。混蛋。下面去反编译看看他的源码。。

namespace log4net.Appender
{
  public class TelnetAppender : AppenderSkeleton
  {
    private static readonly Type declaringType = typeof (TelnetAppender);
    private int m_listeningPort = 23;
    private TelnetAppender.SocketHandler m_handler;

    public int Port
    {
      get
      {
        return this.m_listeningPort;
      }
      set
      {
        if (value < 0 || value > (int) ushort.MaxValue)
          throw SystemInfo.CreateArgumentOutOfRangeException("value", (object) value, "The value specified for Port is less than " + 0.ToString((IFormatProvider) NumberFormatInfo.InvariantInfo) + " or greater than " + ((int) ushort.MaxValue).ToString((IFormatProvider) NumberFormatInfo.InvariantInfo) + ".");
        this.m_listeningPort = value;
      }
    }

    protected override bool RequiresLayout
    {
      get
      {
        return true;
      }
    }

    protected override void OnClose()
    {
      base.OnClose();
      if (this.m_handler == null)
        return;
      this.m_handler.Dispose();
      this.m_handler = (TelnetAppender.SocketHandler) null;
    }

    public override void ActivateOptions()
    {
      base.ActivateOptions();
      try
      {
        LogLog.Debug(TelnetAppender.declaringType, "Creating SocketHandler to listen on port [" + (object) this.m_listeningPort + "]");
        this.m_handler = new TelnetAppender.SocketHandler(this.m_listeningPort);
      }
      catch (Exception ex)
      {
        LogLog.Error(TelnetAppender.declaringType, "Failed to create SocketHandler", ex);
        throw;
      }
    }

    protected override void Append(LoggingEvent loggingEvent)
    {
      if (this.m_handler == null || !this.m_handler.HasConnections)
        return;
      this.m_handler.Send(this.RenderLoggingEvent(loggingEvent));
    }

    protected class SocketHandler : IDisposable
    {
      private ArrayList m_clients = new ArrayList();
      private const int MAX_CONNECTIONS = 20;
      private Socket m_serverSocket;

      public bool HasConnections
      {
        get
        {
          ArrayList clients = this.m_clients;
          if (clients != null)
            return clients.Count > 0;
          return false;
        }
      }

      public SocketHandler(int port)
      {
        this.m_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        this.m_serverSocket.Bind((EndPoint) new IPEndPoint(IPAddress.Any, port));
        this.m_serverSocket.Listen(5);
        this.AcceptConnection();
      }

      private void AcceptConnection()
      {
        this.m_serverSocket.AcceptAsync().ContinueWith(new Action<Task<Socket>>(this.OnConnect), TaskScheduler.Default);
      }

      public void Send(string message)
      {
        foreach (TelnetAppender.SocketHandler.SocketClient client in this.m_clients)
        {
          try
          {
            client.Send(message);
          }
          catch (Exception ex)
          {
            client.Dispose();
            this.RemoveClient(client);
          }
        }
      }

      private void AddClient(TelnetAppender.SocketHandler.SocketClient client)
      {
        TelnetAppender.SocketHandler socketHandler = this;
        bool lockTaken = false;
        try
        {
          Monitor.Enter((object) socketHandler, ref lockTaken);
          ArrayList arrayList = (ArrayList) this.m_clients.Clone();
          arrayList.Add((object) client);
          this.m_clients = arrayList;
        }
        finally
        {
          if (lockTaken)
            Monitor.Exit((object) socketHandler);
        }
      }

      private void RemoveClient(TelnetAppender.SocketHandler.SocketClient client)
      {
        TelnetAppender.SocketHandler socketHandler = this;
        bool lockTaken = false;
        try
        {
          Monitor.Enter((object) socketHandler, ref lockTaken);
          ArrayList arrayList = (ArrayList) this.m_clients.Clone();
          arrayList.Remove((object) client);
          this.m_clients = arrayList;
        }
        finally
        {
          if (lockTaken)
            Monitor.Exit((object) socketHandler);
        }
      }

      private void OnConnect(Task<Socket> acceptTask)
      {
        try
        {
          Socket result = acceptTask.GetAwaiter().GetResult();
          LogLog.Debug(TelnetAppender.declaringType, "Accepting connection from [" + result.RemoteEndPoint.ToString() + "]");
          TelnetAppender.SocketHandler.SocketClient client = new TelnetAppender.SocketHandler.SocketClient(result);
          int count = this.m_clients.Count;
          if (count < 20)
          {
            try
            {
              client.Send("TelnetAppender v1.0 (" + (object) (count + 1) + " active connections)\r\n\r\n");
              this.AddClient(client);
            }
            catch
            {
              client.Dispose();
            }
          }
          else
          {
            client.Send("Sorry - Too many connections.\r\n");
            client.Dispose();
          }
        }
        catch
        {
        }
        finally
        {
          if (this.m_serverSocket != null)
            this.AcceptConnection();
        }
      }

      public void Dispose()
      {
        foreach (TelnetAppender.SocketHandler.SocketClient client in this.m_clients)
          client.Dispose();
        this.m_clients.Clear();
        Socket serverSocket = this.m_serverSocket;
        this.m_serverSocket = (Socket) null;
        try
        {
          serverSocket.Shutdown(SocketShutdown.Both);
        }
        catch
        {
        }
        try
        {
          CompatibilityExtensions.Close(serverSocket);
        }
        catch
        {
        }
      }

      protected class SocketClient : IDisposable
      {
        private Socket m_socket;
        private StreamWriter m_writer;

        public SocketClient(Socket socket)
        {
          this.m_socket = socket;
          try
          {
            this.m_writer = new StreamWriter((Stream) new NetworkStream(socket));
          }
          catch
          {
            this.Dispose();
            throw;
          }
        }

        public void Send(string message)
        {
          this.m_writer.Write(message);
          this.m_writer.Flush();
        }

        public void Dispose()
        {
          try
          {
            if (this.m_writer != null)
            {
              CompatibilityExtensions.Close(this.m_writer);
              this.m_writer = (StreamWriter) null;
            }
          }
          catch
          {
          }
          if (this.m_socket == null)
            return;
          try
          {
            this.m_socket.Shutdown(SocketShutdown.Both);
          }
          catch
          {
          }
          try
          {
            CompatibilityExtensions.Close(this.m_socket);
          }
          catch
          {
          }
          this.m_socket = (Socket) null;
        }
      }
    }
  }
}
View Code

那就没办法。。我自己再重写一个直接发送的TcpAppender吧。。写法是完全看udpAppender源码改的。暴露出来的配置和udp基本一致。把local的去除了

    internal class TcpAppender : AppenderSkeleton
    {
        private Encoding _encoding = Encoding.Unicode;
        private IPAddress _remoteAddress;
        private int _remotePort;
        private IPEndPoint _remoteEndPoint;
        private TcpClient _client;

        public IPAddress RemoteAddress
        {
            get
            {
                return this._remoteAddress;
            }
            set
            {
                this._remoteAddress = value;
            }
        }

        public int RemotePort
        {
            get
            {
                return this._remotePort;
            }
            set
            {
                if (value < 0 || value > (int)ushort.MaxValue)
                    throw SystemInfo.CreateArgumentOutOfRangeException("value", (object)value, "The value specified is less than " + 0.ToString((IFormatProvider)NumberFormatInfo.InvariantInfo) + " or greater than " + ((int)ushort.MaxValue).ToString((IFormatProvider)NumberFormatInfo.InvariantInfo) + ".");
                this._remotePort = value;
            }
        }

        public Encoding Encoding
        {
            get
            {
                return this._encoding;
            }
            set
            {
                this._encoding = value;
            }
        }

        protected TcpClient Client
        {
            get
            {
                return this._client;
            }
            set
            {
                this._client = value;
            }
        }

        protected IPEndPoint RemoteEndPoint
        {
            get
            {
                return this._remoteEndPoint;
            }
            set
            {
                this._remoteEndPoint = value;
            }
        }

        protected override bool RequiresLayout
        {
            get
            {
                return true;
            }
        }

        public override void ActivateOptions()
        {
            base.ActivateOptions();
            if (this.RemoteAddress == null)
                throw new ArgumentNullException("The required property 'Address' was not specified.");
            if (this.RemotePort < 0 || this.RemotePort > (int)ushort.MaxValue)
                throw SystemInfo.CreateArgumentOutOfRangeException("this.RemotePort", (object)this.RemotePort, "The RemotePort is less than " + 0.ToString((IFormatProvider)NumberFormatInfo.InvariantInfo) + " or greater than " + ((int)ushort.MaxValue).ToString((IFormatProvider)NumberFormatInfo.InvariantInfo) + ".");
            this.RemoteEndPoint = new IPEndPoint(this.RemoteAddress, this.RemotePort);
            this.InitializeClientConnection();
        }

        protected override void Append(LoggingEvent loggingEvent)
        {
            try
            {
                NetworkStream ntwStream = this.Client.GetStream();
                var aa = this.RenderLoggingEvent(loggingEvent).ToCharArray();
                byte[] bytes = this._encoding.GetBytes(this.RenderLoggingEvent(loggingEvent).ToCharArray());
                ntwStream.Write(bytes, 0, bytes.Length);
            }
            catch (Exception ex)
            {
                this.ErrorHandler.Error("Unable to send logging event to remote host " + this.RemoteAddress.ToString() + " on port " + (object)this.RemotePort + ".", ex, ErrorCode.WriteFailure);
            }
        }

        protected override void OnClose()
        {
            base.OnClose();
            if (this.Client == null)
                return;
            Client.Dispose();
            this.Client = null;
        }

        protected virtual void InitializeClientConnection()
        {
            try
            {
                this.Client = new TcpClient(this.RemoteAddress.ToString(), this.RemotePort);
            }
            catch (Exception ex)
            {
                this.ErrorHandler.Error("Could not initialize the UdpClient connection on port " + this.RemotePort.ToString((IFormatProvider)NumberFormatInfo.InvariantInfo) + ".", ex, ErrorCode.GenericFailure);
                this.Client = null;
            }
        }
    }
View Code

用法代码。里面额外加入了一个consoleAppender 方便查看调试

 1         static void Main(string[] args)
 2         {
 3             Test();
 4             Console.ReadKey();
 5         }
 6 
 7         private static void Test()
 8         {
 9             var repo = LogManager.CreateRepository("R");
10 
11             var layout = new PatternLayout()
12             {
13                 ConversionPattern = "#%date #%level #%message#",
14             };
15             var tcpAppender = new TcpAppender
16             {
17                 Encoding = Encoding.UTF8,
18                 RemoteAddress = new IPAddress(new byte[] { 192,168,132,128 }),
19                 RemotePort = 8001,
20                 Layout = layout
21             };
22             var consoleAppender = new ConsoleAppender
23             {
24                 Layout = layout
25             };
26             layout.ActivateOptions();
27             tcpAppender.ActivateOptions();
28             BasicConfigurator.Configure(repo, consoleAppender,tcpAppender);
29 
30             ILog log = LogManager.GetLogger(repo.Name, "Debug");
31             log.Info("666666666666666666666");
32             Console.ReadKey();
33         }
View Code

 

下面是成功发送到虚拟机上的kibana的后台显示。部分数据和字段没匹配好是logstash的规则和log4net规则没对应好

 

posted @ 2018-01-26 10:55  TeemoHQ  阅读(1067)  评论(1编辑  收藏  举报