首先要确定需要的参数,ID是必须的,其次日志得含有日期,标题,内容,日志类型。查询日志一般来说是通过开始时间,结束时间,日志类型来查询。
model层建立LogsInfo
public class LogsInfo
{
public int LId { get; set; }
public string LDataTime { get; set; }
public string LTitle { get; set; }
public string LContent { get; set; }
public LogsType LType { get; set; }
}
public enum LogsType
{
所有信息,
错误信息,
警告信息,
运行信息
}
public class LogsQuery
{
public DateTime starttime { get; set; }
public DateTime endtime { get; set; }
public LogsType LType { get; set; }
}
这里因为日志一般数据量很大,且保存时间较久,这里不使用sqlite,我们改用mysql
通过上面参数设计mysql表格
Dal层建立mysql通用方法类
public class MysqlHelper
{
private static readonly string conStr = "Database='mydatabase';Data Source='localhost';Port='3360';User Id='root';Password='123456';charset='utf8';pooling=true";
///
/// 1、执行增(insert) 删(delete) 改(update) 的方法
///
///
///
///
public static int ExecuteNonQuery(string sql, params MySqlParameter[] pms)
{
using (MySqlConnection con = new MySqlConnection(conStr))
{
using (MySqlCommand cmd = new MySqlCommand(sql, con))
{
if (pms.Length>0)
{
if (pms[0] != null)
{
cmd.Parameters.AddRange(pms);
}
}
con.Open();
return cmd.ExecuteNonQuery();
}
}
}
///
/// 2、执行查询,返回单个值的方法
///
///
///
///
public static object ExecuteScalar(string sql, params MySqlParameter[] pms)
{
using (MySqlConnection con = new MySqlConnection(conStr))
{
using (MySqlCommand cmd = new MySqlCommand(sql, con))
{
if (pms != null)
{
cmd.Parameters.AddRange(pms);
}
con.Open();
return cmd.ExecuteScalar();
}
}
}
///
/// 3、执行查询,返回多行多列的方法
///
///
///
///
public static MySqlDataReader ExecuteReader(string sql, params MySqlParameter[] pms)
{
MySqlConnection con = new MySqlConnection(conStr);
using (MySqlCommand cmd = new MySqlCommand(sql, con))
{
if (pms != null)
{
cmd.Parameters.AddRange(pms);
}
try
{
con.Open();
//这个枚举参数,表示将来使用完毕reader后,在关闭reader的
//同时,在sqldatareader内部会将关联的connection对象也关闭掉
return cmd.ExecuteReader
(System.Data.CommandBehavior.CloseConnection);
}
catch
{
con.Close();
con.Dispose();
throw;
}
}
}
///
/// 4、查询数据返回DataTable
///
///
///
///
public static DataTable ExecuteDataTable(string sql, params MySqlParameter[] pms)
{
try
{
//构造连接对象
using (MySqlConnection conn = new MySqlConnection(conStr))
{
//构造桥接器对象
MySqlDataAdapter adapter = new MySqlDataAdapter(sql, conn);
//加参数查找
if (pms[0] != null)
{
adapter.SelectCommand.Parameters.AddRange(pms);
}
//数据表对象
DataTable table = new DataTable();
//将数据存到table中
adapter.Fill(table);
//返回数据表
return table;
}
}
catch (Exception ex)
{
DataTable table = new DataTable();
return table;
}
}
建立好通用方法后,我们接着在Dal声名类
public class LogsDal
{
///
/// 插入
///
///
///
public int Insert(LogsInfo li)
{
//构造sql语句
string sql =
"insert into Logs(LDataTime,LTitle,LContent,LType) values(@datatime,@title,@content,@type)";
//数组的初始化器
MySqlParameter[] ps =
{
new MySqlParameter("@datatime",li.LDataTime),
new MySqlParameter("@title",li.LTitle),
new MySqlParameter("@content",li.LContent),
new MySqlParameter("@type",li.LType.ToString()),
};
//执行
return MysqlHelper.ExecuteNonQuery(sql, ps);
}
///
/// 删除n天以外的日志
///
///
///
public int DeleteTime(int date)
{
///DELETE FROM 表名 WHERe 时间字段 BETWEEN 开始时间 AND 结束时间
///DELETe FROM 表名 WHERe 时间字段>=开始时间 AND 时间字段<=结束时间
string sql = "delete From `logs` where DATE(LDataTime) <= DATE(DATE_SUB(NOW(),INTERVAL @time day)) ";
MySqlParameter[] ps =
{
new MySqlParameter("@time",date)
};
return MysqlHelper.ExecuteNonQuery(sql, ps);
}
///
/// 清空表
///
///
public int EmptyTable()
{
string sql = "truncate Logs";
return MysqlHelper.ExecuteNonQuery(sql);
}
///
/// 删除在n-k之间的数据
///
///
///
public int Delete(DateTime startdate,DateTime endtime)
{
///DELETE FROM 表名 WHERe 时间字段 BETWEEN 开始时间 AND 结束时间
///DELETe FROM 表名 WHERe 时间字段>=开始时间 AND 时间字段<=结束时间
string sql = "delete From `logs` where LDataTime between @starttime and @endtime";
MySqlParameter[] ps =
{
new MySqlParameter("@starttime",startdate),
new MySqlParameter("@endtime",endtime)
};
return MysqlHelper.ExecuteNonQuery(sql, ps);
}
///
/// 通过时间来查找数据
/// 包含开始时间,结束时间,信息类型
///
///
public List Getlist(LogsQuery lq)
{
List list = new List();
List sqllist = new List();
string sql = "select * from Logs where LDataTime>= @starttime and LDataTime<=@endtime";
sqllist.Add(new MySqlParameter("@starttime", lq.starttime));
sqllist.Add(new MySqlParameter("@endtime", lq.endtime));
if (lq.LType != LogsType.所有信息)
{
sql = String.Concat(sql, " and LType=@type");
sqllist.Add(new MySqlParameter("@type", lq.LType.ToString()));
}
using (MySqlDataReader reader = MysqlHelper.ExecuteReader(sql, sqllist.ToArray()))
{
if (reader.HasRows)
{
while (reader.Read())
{
LogsInfo model = new LogsInfo()
{
LId = reader.GetInt32(0),
LDataTime = reader.GetString(1),
LTitle = reader.GetString(2),
LContent = reader.GetString(3),
LType = (LogsType)Enum.Parse(typeof(LogsType), reader.GetString(4))
};
list.Add(model);
}
}
}
return list;
}
}
这里由于要对查询出来的数据进行整理分页
所以在COMMON层声名
public class LogsHelper
{
///
/// 把一个集合分割成一个集合为num个数的集合
///
///
///
///
///
public static List> SpiltList(List Lists, int num) //where T:class
{
List> fz = new List>();
//组数
int GroupNum;
//元素数量大于等于 一组的个数
if (Lists.Count >= num)
{
if (Lists.Count % num == 0)
{
GroupNum = Lists.Count / num;
}
else
{
GroupNum = Lists.Count / num + 1;
}
//给每一组分配元素
for (int i = 0; i < GroupNum; i++)
{
List cList = new List();
if (i + 1 == GroupNum)
{
cList = Lists.Skip(num * i).ToList();
}
else
{
cList = Lists.Skip(num * i).Take(num).ToList();
}
fz.Add(cList);
}
}
else
{
fz.Add(Lists);//元素数量小于分组数量
}
return fz;
}
}
随后我们在Bll层建立LogsBll
#region << 版 本 注 释 >>
#endregion
public class LogsBll
{
LogsDal Dal = new LogsDal();
///
/// 私有化构造函数
///
private LogsBll()
{
}
///
/// 声名一个静态变量
///
private static LogsBll LoList;
///
/// 单例模式
///
///
public static LogsBll Create()
{
if (LoList == null)
{
LoList = new LogsBll();
}
return LoList;
}
///
/// 获得日志集合
///
///
private List GetList(LogsQuery lq)
{
return Dal.Getlist(lq);
}
///
/// 插入一行数据
///
///
///
public bool Add(LogsInfo li)
{
return Dal.Insert(li) > 0;
}
///
/// 移除
///
///
///
public bool Remove(int date)
{
return Dal.DeleteTime(date) > 0;
}
///
/// 清空表格
///
///
public bool EmptyTable()
{
return Dal.EmptyTable() > 0;
}
///
/// 删除在n-k时间之间的数据
///
///
///
///
public bool Delete(DateTime startdate, DateTime endtime)
{
return Dal.Delete(startdate, endtime) > 0;
}
///
/// 查询日志 并将数据分割成 多个集合
///
///
///
public List> Getlists(LogsQuery lq)
{
return LogsHelper.SpiltList(GetList(lq), 50);
}
}
最后在UI层设计数据库查询界面
日志可通过日期+类型查询
将查询出来的日志50条为一页进行切割并显示查询的总条数,总页数
public partial class LogsForm : Form
{
public LogsForm()
{
InitializeComponent();
Init();
}
public void Init()
{
this.Text = "";
this.dgvLogs.ReadOnly = true;
cbxType.DataSource = Enum.GetNames(typeof(LogsType));
_pages = 0;
}
LogsBll bll = LogsBll.Create();
List> list=new List>();
private int _pages;
private void RefreshTips()
{
this.lblCurrentPage.Text =String.Format("第{0}页",_pages);
this.lblAllPage.Text = String.Format("共{0}页",list.Count);
this.lblNum.Text= String.Format("共{0}条记录",50 * (list.Count - 1) + list[list.Count - 1].Count);
}
private void btnQuert_Click(object sender, EventArgs e)
{
this.BeginInvoke(new Action(() =>
{
Cursor.Current = Cursors.WaitCursor;
LogsQuery lq = new LogsQuery()
{
starttime = dataTimeStart.Value,
endtime = dataTimeEnd.Value,
LType = (LogsType)Enum.Parse(typeof(LogsType), cbxType.Text)
};
list = bll.Getlists(lq);
List list1 = list[0];
if (list.Count > 0)
{
dgvLogs.DataSource = list[0];
_pages = 1;
RefreshTips();
}
}));
Cursor.Current= Cursors.Default;
}
private void btnHomePage_Click(object sender, EventArgs e)
{
this.BeginInvoke(new Action(() =>
{
if (list.Count > 0)
{
dgvLogs.DataSource = list[0];
_pages = 1;
RefreshTips();
}
else
{
return;
}
}));
}
private void btnEndPage_Click(object sender, EventArgs e)
{
this.BeginInvoke(new Action(() =>
{
if (list.Count > 0)
{
dgvLogs.DataSource = list[list.Count - 1];
_pages = list.Count;
RefreshTips();
}
else
{
return;
}
}));
}
private void btnPreviousPage_Click(object sender, EventArgs e)
{
this.BeginInvoke(new Action(() =>
{
if (list.Count > 0)
{
if(_pages > 1)
{
_pages--;
dgvLogs.DataSource = list[_pages-1];
RefreshTips();
}
}
else
{
return;
}
}));
}
private void btnNextPage_Click(object sender, EventArgs e)
{
this.BeginInvoke(new Action(() =>
{
if (list.Count > 0)
{
if (_pages < list.Count)
{
_pages++;
dgvLogs.DataSource = list[_pages-1];
RefreshTips();
}
}
else
{
return;
}
}));
}
}
设计删除日志的UI
public partial class LogsSetingFrom : Form
{
public LogsSetingFrom()
{
InitializeComponent();
}
public void Init()
{
this.FormBorderStyle = FormBorderStyle.None;
this.ControlBox = false;
this.Text = "";
}
LogsBll bll = LogsBll.Create();
private void btnDelect_Click(object sender, EventArgs e)
{
bll.EmptyTable();
MessageBox.Show("删除成功");
}
private void btnDelectBetween_Click(object sender, EventArgs e)
{
bll.Delete(dtpStart.Value, dtpend.Value);
MessageBox.Show("删除成功");
}
}
软件实时运行的日志界面
首先需要先建立一个队列用来存储日志内容,通过任务或者线程来对日志进行不断地写入,显示
到界面上
Bll层声名
#region << 版 本 注 释 >>
#endregion
public class LogsQueue
{
///
/// 日志队列 用于MainFrom中日志textbox控件展示日志使用
///
private static ConcurrentQueue RunningLogQueue = new ConcurrentQueue();
///
/// 向UI日志显示队列中添加一个对象
///
///
public static void RunningLogQueue_AddOne(LogsInfo log)
{
log.LDataTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
RunningLogQueue.Enqueue(log);
}
///
/// 从UI日志队列中取出一个对象
///
///
///
public static bool RunningLogQueue_GetOne(out LogsInfo log)
{
return RunningLogQueue.TryDequeue(out log);
}
///
/// 判断UI日志队列中是否有对象
///
///
public static bool RunningLogQueue_HaveElement()
{
if (RunningLogQueue.Count <= 0)
{
return false;
}
else
{
return true;
}
}
}
接着继续在Bll层声名任务,这里需要使用到Action事件,用来传递数据到UI层
#region << 版 本 注 释 >>
#endregion
public class TaskLogs
{
LogsBll logbll;
SystemSetBll ssbll;
//定义事件
public event Action SentLogsTxt;
public TaskLogs()
{
logbll = LogsBll.Create();
ssbll= SystemSetBll.Create();
Task_UpdateRunningLog();
}
private CancellationTokenSource tskQueue1_cts = null;
private void Task_UpdateRunningLog()
{
tskQueue1_cts = new CancellationTokenSource();
Task task1 = new Task(() => { UpdateRunningLog(); }, tskQueue1_cts.Token, TaskCreationOptions.LongRunning);
task1.Start();
}
private void UpdateRunningLog()
{
try
{
while (!tskQueue1_cts.IsCancellationRequested)
{
if (LogsQueue.RunningLogQueue_HaveElement())
{
LogsInfo log = null;
if (LogsQueue.RunningLogQueue_GetOne(out log))
{
logbll.Add(log);//写入数据库
if (SentLogsTxt != null)
{
SentLogsTxt(log);//显示界面
}
SaveLog(log);
}
}
Thread.Sleep(10);
}
}
catch (Exception ex)
{
throw ex;
}
}
private void SaveLog(LogsInfo log)
{
try
{
string kk = ssbll.GetValue(PName.日志存放地址);
if (!Directory.Exists(ssbll.GetValue(PName.日志存放地址)))
{
Directory.CreateDirectory(ssbll.GetValue(PName.日志存放地址));
}
string df = DateTime.Now.ToLongDateString();
string addressErrorLog = ssbll.GetValue(PName.日志存放地址) + "\" + df + @"_other.txt";
if (!File.Exists(addressErrorLog)) File.Create(addressErrorLog).Close();
StringBuilder strBuilderErrorMessage = new StringBuilder();
strBuilderErrorMessage.Append("日期:" + log.LDataTime + "rn");
strBuilderErrorMessage.Append("标题:" + log.LTitle + "rn");
strBuilderErrorMessage.Append("内容:"+log.LContent + "rn");
strBuilderErrorMessage.Append("类型:" + log.LType.ToString() + "rn");
strBuilderErrorMessage.Append("___________________________________________________rn");
using (FileStream fs = new FileStream(addressErrorLog, FileMode.Append, FileAccess.Write))
{
StreamWriter sw = new StreamWriter(fs, Encoding.Default);
sw.WriteLine(strBuilderErrorMessage);
sw.Close();
fs.Close();
}
}
catch (Exception ex) {
throw ex;
}
}
}
最后设计软件运行得实时日志UI
这里使用委托来显示数据到界面上
public partial class LogsMainFrom : Form
{
public LogsMainFrom()
{
InitializeComponent();
tlogs.SentLogsTxt += ShowLogs;
}
TaskLogs tlogs=new TaskLogs();
private void LogsMainFrom_Load(object sender, EventArgs e)
{
this.FormBorderStyle = FormBorderStyle.None;
this.ControlBox = false;
this.Text = "";
this.tbxLogs.ReadOnly = true;
}
private void ShowLogs(LogsInfo logs)
{
Invoke(new Action(() =>
{
if (this.tbxLogs.Lines.Length > 1000) this.tbxLogs.Clear();//如果超过1000行,日志清零
string msg = String.Concat(logs.LDataTime ," " ,logs.LTitle + " " ,logs.LContent + " " ,logs.LType.ToString() , "rn");
this.tbxLogs.AppendText(msg);//显示日志到界面上
this.tbxLogs.Select(this.tbxLogs.TextLength, 0);//光标定位到文本最后
}));
}
}



