基于文件的日志服务器,基于.NetCore的日志服务器

系统日志是观察系统运行情况的窗口,它可以帮助我们快速定位错误、发现系统性能瓶颈甚至可以分析用户行为等。下面基于.NetCore开发的一套简单的日志服务器,供大家交流学习。

一、为什么要单独实现日志服务器:

1、系统日志操作(写日志)是一个频率非常高的操作,当系统用户量达到一定程度后,对于高频的日志操作很有可能会成为系统的性能瓶颈

2、实现日志处理与系统的解耦

3、有利于系统的扩展(如果日志单台日志服务器到达负载了,再加一台日志服务器就行)

4、利于日志的集中管理

二、采用什么方式实现日志服务器

1、日志的传输采用tcp协议进行传输

2、日志服务器是监听了指定ip和端口的socket服务器

3、服务器的日志操作采用多线程,充分利用服务器资源

三、如何实现日志服务器

1、安装.NetCore连接数据库的驱动程序(我这里使用的是mysql),便于将日志信息保存到数据中

Install-Package MySql.Data -Version 8.0.15

2、安装Log4Net,当日志服务器发生异常的时候记录异常日志到文件中,便于后期进行错误处理

Install-Package log4net -Version 2.0.8

2.1、配置Log4Net

2.2、实现LogHelper类,这个类主要用于文件日志的记

using log4net;

using log4net.Appender;

using log4net.Config;

using log4net.Repository;

using System;

using System.IO;

namespace LogServer

{

///

/// 日志帮助类

///

public class LogHelper

{

private static ILog Logger { get; set; }

static LogHelper()

{

if (Logger == null)

{

//log4net注册

ILoggerRepository loggerRepository = LogManager.CreateRepository("NETCoreRepository");

XmlConfigurator.Configure(loggerRepository, new FileInfo("log4net.config"));

Logger = LogManager.GetLogger(loggerRepository.Name, "InfoLogger");

IAppender[] appenders = loggerRepository.GetAppenders();

///打印日志的保存路径

foreach (var appender in appenders)

{

RollingFileAppender rollingFileAppender = appender as RollingFileAppender;

Console.WriteLine(rollingFileAppender.File);

}

}

}

///

/// 调试信息

///

///

///

public static void Debug(string msg, Exception ex = null)

{

if (ex == null)

{

Logger.Debug(msg);

}

else

{

Logger.Debug(msg, ex);

}

}

//错误信息

public static void Error(string msg, Exception ex = null)

{

if (ex == null)

{

Logger.Error(msg);

}

else

{

Logger.Error(msg, ex);

}

}

}

}

3、客户端数据处理类

using MySql.Data.MySqlClient;

using System;

using System.Collections.Generic;

using System.Net.Sockets;

using System.Text;

using System.Threading;

namespace LogServer

{

public class TcpClientManager

{

private TcpListener _TcpListener { get; set; }

private TcpClient _TcpClient { get; set; }

public TcpClientManager(TcpListener tcpListener, TcpClient tcpClient)

{

this._TcpClient = tcpClient;

this._TcpListener = tcpListener;

}

public void DealClientData()

{

StringBuilder sb = new StringBuilder();

try

{

//1、获取客户端数据流

NetworkStream networkStream = this._TcpClient.GetStream();

//2、创建网络流中自定义数据类型(int类型的存储占用4个字节)

byte[] dataLenByte = new byte[4];

byte[] dataTypeByte = new byte[4];

//3、获取自定义数据值

int readCount = networkStream.Read(dataLenByte, 0, dataLenByte.Length);

while (readCount > 0)

{

//3.1、获取自定义数据

networkStream.Read(dataTypeByte, 0, dataTypeByte.Length);

int dataLen = BitConverter.ToInt32(dataLenByte, 0);

int dataType = BitConverter.ToInt32(dataTypeByte, 0);

if (dataLen > 0)

{

//读取数据

byte[] data = new byte[dataLen];

int readedDataLen = 0;

while (dataLen - readedDataLen > 0)

{

int dataBufferReadCount = 0;

if (dataLen - readedDataLen >= 1024)

{

dataBufferReadCount = 1024;

}

else

{

dataBufferReadCount = dataLen - readedDataLen;

}

//读取数据到缓冲区

byte[] dataBuffer = new byte[dataBufferReadCount];

int tempReadCount = networkStream.Read(dataBuffer, 0, dataBuffer.Length);

//拷贝数据到数据容器中

dataBuffer.CopyTo(data, readedDataLen);

readedDataLen += tempReadCount;

}

sb.Append($"({dataType},'{Encoding.UTF8.GetString(data)}'),");

}

//读取当前客户端连接的下一条数据

readCount = networkStream.Read(dataLenByte, 0, dataLenByte.Length);

}

if (!string.IsNullOrEmpty(sb.ToString()))

{

using (MySqlConnection conn =

new MySqlConnection("server=127.0.0.1;database=Log;uid=root;pwd=root;charset=utf8;"))

{

using (MySqlCommand cmd = conn.CreateCommand())

{

conn.Open();

cmd.CommandText = $"insert into apilog(`Type`,`Msg`) values {sb.ToString().TrimEnd(',')}";

cmd.ExecuteNonQuery();

}

}

}

}

catch (Exception ex)

{

Console.WriteLine($"保存日志信息发生异常:{ex}");

LogHelper.Error("保存日志信息发生异常", ex);

}

finally

{

//关闭客户端连接

this._TcpClient.Close();

}

}

}

}

4、主程序

using MySql.Data.MySqlClient;

using System;

using System.IO;

using System.Net;

using System.Net.Sockets;

using System.Threading;

namespace LogServer

{

class Program

{

static void Main(string[] args)

{

Thread tcpListenerThread = new Thread(() =>

{

IPEndPoint ipEndPoint=new IPEndPoint(IPAddress.Any,8888);

TcpListener tcpServer = new TcpListener(ipEndPoint);

tcpServer.Start(100);

while (true)

{

Console.WriteLine("日志服务器正在运行中...");

TcpClient tcpClient = tcpServer.AcceptTcpClient();

Console.WriteLine("请求来了!开始处理...");

TcpClientManager tcpClientManager = new TcpClientManager(tcpServer, tcpClient);

Thread tcpClientThread = new Thread(tcpClientManager.DealClientData);

tcpClientThread.IsBackground = true;

tcpClientThread.Start();

}

});

tcpListenerThread.IsBackground = true;

tcpListenerThread.Start();

while (true)

{

Console.WriteLine("日志服务器正在运行中...");

Console.ReadKey();

}

}

}

}

5、写日志测试

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net.Sockets;

using System.Text;

using System.Threading.Tasks;

using Microsoft.AspNetCore.Mvc;

namespace ApiServer.Controllers

{

[Route("api/[controller]")]

[ApiController]

public class ValuesController : ControllerBase

{

// GET api/values

[HttpGet]

public ActionResult Get(string msg)

{

try

{

using (TcpClient tcpClient = new TcpClient("127.0.0.1", 8888))

{

if (string.IsNullOrEmpty(msg))

{

return "请传正确的请求参数";

}

//发送日志数据

for (int i = 0; i < 100; i++)

{

byte[] sourceData = Encoding.UTF8.GetBytes(msg);

byte[] dataLen = BitConverter.GetBytes(sourceData.Length);

byte[] dataType = BitConverter.GetBytes(1);

byte[] sendData = new byte[sourceData.Length + 8];

dataLen.CopyTo(sendData, 0);

dataType.CopyTo(sendData, 4);

sourceData.CopyTo(sendData, 8);

tcpClient.Client.Send(sendData);

}

//关闭与日志服务器的连接

tcpClient.Close();

}

}

catch (Exception ex)

{

return ex.Message;

}

return "日志保存成功";

}

}

}

915e4f024fdd

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值