在您的应用程序中直接使用 PaperTrail 进行日志记录





5.00/5 (3投票s)
一个精简版系列文章。
(您多久能看到一个以字节为单位计量的下载?不是 KB,不是 MB,而是纯粹的“B”?“B”代表“极简”!)
引言
PaperTrail 是一个巧妙的 Web 应用程序,可以记录您发送给它的任何消息。我在这里介绍的是一个极简的 UDP 和 TCP 接口,用于在 PaperTrail 上记录消息。编写此代码的初衷是 PaperTrail 的理念侧重于能够连接到系统日志的客户端工具和/或使用第三方日志应用程序(例如 log4net)。对于 Windows,PaperTrail 建议使用“nxlog”。如果您不是开发人员和/或特别有兴趣使用 PaperTrail 远程查看您的系统事件,这一切都没问题。另外,如果您使用 log4net 等日志记录器,您可以使用 appender 来记录到 PaperTrail。然而,我的情况并非如此——我想学习如何在我的应用程序中直接使用 PaperTrail,并且我不想使用 log4net 这样的第三方组件。
我在这里介绍的实现大量借鉴了 Matthew Fittchett 的 PaperTrailTLS 代码。我的贡献是将其制作成一个真正小巧的可重用库,而不是演示代码,并解决 Matthew 示例中的一些性能问题。
创建 PaperTrail 帐户
创建 PaperTrail 帐户后...
如何向 PaperTrail 写入日志条目?
您将写入的 URL 和端口位于您的“帐户 -> 日志目标”下(我已从图片中删除了我的端口号)
或者,如果您转到“系统设置”页面,您会在页面顶部看到它以粗体大字显示
我的 API 令牌在哪里?
如果您有兴趣远程查询您的日志,您将需要一个 API 令牌。API 令牌位于“我 -> 个人资料”下(同样,我已从屏幕截图中删除了我的 API 令牌)
也许未来的文章将讨论如何使用 REST/JSON 查询 PaperTrail。
UDP 日志记录
UDP 日志记录限制为 1000 个字符条目,一旦您有了 URL 和端口号,它就非常直接。我们需要
using System.Net; using System.Net.Sockets;
然后是实现,允许我们向日志目标的已知 IP 地址或日志目标的 URL 发送日志消息(返回的任何 IP 地址都可以使用)
private static void SendUdpMessage(IPAddress address, int port, string message) { Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); IPEndPoint endPoint = new IPEndPoint(address, port); byte[] buffer = Encoding.ASCII.GetBytes(message); socket.SendTo(buffer, endPoint); socket.Close(); } private static void SendUdpMessage(string url, int port, string message) { IPAddress[] addr = Dns.GetHostAddresses(PaperTrailLogUrl); SendUdpMessage(addr[0], port, message); }
一个简单的测试程序
static string PaperTrailIp = "<your log destination IP>"; static int PaperTrailPort = <your port number>; static string PaperTrailLogUrl = "<your log destination URL"; static void Main(string[] args) { IPAddress addr = IPAddress.Parse(PaperTrailIp); SendUdpMessage(addr, PaperTrailPort, "Hello World via IP address (UDP)"); SendUdpMessage(PaperTrailLogUrl, PaperTrailPort, "Hello World via URL (UDP)"); }
大功告成
TCP 日志记录
TCP 日志记录似乎不再受支持了。至少,我无法使其正常工作。
TLS 日志记录
我们需要
using System.Net.Security; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates;
然后是实现
private static void SendTlsMessage(string url, int port, string message) { const string CRLF = "\r\n"; TcpClient client = new TcpClient(url, port); SslStream sslStream = new SslStream(client.GetStream(), false, ValidateServerCertificate, null); sslStream.AuthenticateAsClient(url); byte[] buffer = Encoding.UTF8.GetBytes(message + CRLF); sslStream.Write(buffer); sslStream.Flush(); sslStream.Close(); client.Close(); } public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return sslPolicyErrors == SslPolicyErrors.None; }
我们必须在 TCP 消息的末尾添加 CR-LF!如果您未能这样做,消息将不会出现在 PaperTrail 上。您会注意到我们不需要对 UDP 消息这样做。
打开连接非常耗时
我们真的不希望为每条日志消息打开一个连接,验证证书(如果使用 TLS),然后关闭连接。这会让您的应用程序运行缓慢。所以,取而代之的是,我们将创建一个持久化连接信息的类,并使用一点继承来分离 UDP 和 TLS 的行为
using System; using System.Net; using System.Net.Sockets; using System.Net.Security; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Text; namespace PaperTrailDemo { public abstract class PaperTrailLogger { protected IPAddress ip; protected int port; protected string url; public PaperTrailLogger(string url, int port) { IPAddress[] addr = Dns.GetHostAddresses(url); ip = addr[0]; this.url = url; this.port = port; } public abstract void Open(); public abstract void Close(); public abstract void Log(string message); } public class UdpPaperTrailLogger : PaperTrailLogger { protected Socket socket; protected IPEndPoint endPoint; public UdpPaperTrailLogger(string url, int port) : base(url, port) { } public override void Open() { socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); endPoint = new IPEndPoint(ip, port); } public override void Close() { socket.Close(); } public override void Log(string message) { byte[] buffer = Encoding.ASCII.GetBytes(message); socket.SendTo(buffer, endPoint); socket.Close(); } } public class TlsPaperTrailLogger : PaperTrailLogger { protected TcpClient client; protected SslStream sslStream; public TlsPaperTrailLogger(string url, int port) : base(url, port) { } public override void Open() { client = new TcpClient(url, port); sslStream = new SslStream(client.GetStream(), false, ValidateServerCertificate, null); sslStream.AuthenticateAsClient(url); } public override void Close() { sslStream.Close(); client.Close(); } public override void Log(string message) { const string CRLF = "\r\n"; byte[] buffer = Encoding.UTF8.GetBytes(message + CRLF); sslStream.Write(buffer); sslStream.Flush(); } private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return sslPolicyErrors == SslPolicyErrors.None; } } }
这样可以使我们的使用更清晰
UdpPaperTrailLogger logger = new UdpPaperTrailLogger(PaperTrailLogUrl, PaperTrailPort); logger.Open(); logger.Log("UDP - Hello!"); logger.Close(); TlsPaperTrailLogger logger2 = new TlsPaperTrailLogger(PaperTrailLogUrl, PaperTrailPort); logger2.Open(); logger2.Log("TLS - Hello!"); logger2.Close();
大功告成(再次)
异常应由调用者处理。
深入了解
日志消息符合 RFC-5424“Syslog 协议”。如果您不想阅读 RFC,这里有一个关于该主题的维基百科页面。
例如,我们可以通过发出如下日志消息来编码特定的优先级、系统(“程序”)和“组件”
logger.Log("<22>" + DateTime.Now.ToString("MMM d H:mm:ss") + " Marc Test: This is a test message");
请注意,日期格式必须完全符合此格式。在 PaperTrail 端,结果是
请注意,PaperTrail 自动创建了系统“Marc”。我们可以使用这种更精细的消息粒度来进行警报和查询,我在这里没有涵盖。
客户支持
关于 PaperTrail 的客户支持,简单说一下——我前段时间加入了帮助聊天室,与 Leon 进行了一次非常有帮助的谈话,他为我指明了如何将我的日志“系统”命名为除我的路由器 IP 地址之外的其他名称!我对此印象深刻。
这里有一个 PHP 示例链接,说明了 BSD Syslog 协议。
结论
如果您正在寻找更集成的日志记录,那么请务必使用 nxlog 或 log4net appender。正如我提到的,这里的代码大量借鉴了 Matthew Fittchett 的 PaperTrailTLS 代码。我在这里增加的价值是删除了所有不必要的东西,这样您就可以在一个小的 C# 文件中获得核心功能,并将方法包装在一个持久化连接的类中,而不是为每条日志消息不断地打开、验证、关闭连接。
希望如果您一直在寻找如何在应用程序中直接实现 PaperTrail 日志记录,这篇短文对您有所帮助。