使用MONO在MAC OS上开发——同步日志(一)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 原先打算再写点EXT.NET方面的,由于现在在玩Silverlight和Android,所以不打算写下去了。而且最近很忙,所以发帖也不会很及时。   好了,转入正题了:最近客户有个需求,要求写个小程序监控生产线上的苹果一体机的日志文件并上传到服务器。

  原先打算再写点EXT.NET方面的,由于现在在玩Silverlight和Android,所以不打算写下去了。而且最近很忙,所以发帖也不会很及时。

  好了,转入正题了:最近客户有个需求,要求写个小程序监控生产线上的苹果一体机的日志文件并上传到服务器。开始想使用Perl或者Python,但是时间不够(因为对这两门语言还不太熟悉),于是想试试MONO。MONO虽然没想象中好用,但是还算勉强能用。

  虽然MonoDevelop还可以,但是还是比较喜欢使用VS开发。于是在VS里面先编码。值得注意的是:

  1. 如果是开发Winform程序,界面用GTK重画吧。
  2. 如果是在VS里面开发,最好将所有的编码和注释都用英文。否则换其他系统时,可能会出现乱码。
  3. 编写时需注意MONO是否支持,否则就是白写。

接下来,开始编码。

1.读取配置文件

  习惯用XML,发现不支持System.Xml.Linq,亦不支持System.Xml,读取ini文件也麻烦,于是干脆读取文本文件好了。示例配置如下:

MonitoringDirectoryType:['Immediate','Cycle']

Path:['/Users/PRODUCTION/Public/FinalTest/LogsFolder','/Users/PRODUCTION/Public/FinalTest/LogsFolder']

TargetPath:['/Volumes/mes_data/FINALTEST/n81a/{Y}/{M}/{D}/FIN012','/Volumes/mes_data/FINALTEST/n81a/{Y}/{M}/{D}/FIN012']

IncludeSubdirectories:['FALSE','false']

Filter:['*.TXT','*.CSV']

BackupPath:['/Users/PRODUCTION/BACKUP/{Y}/{M}/{D}','/Users/PRODUCTION/BACKUP/{Y}/{M}/{D}']

BackupExpired:['2','2']

CycleMinutes:['','1440']

相关解析代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using MonitoringApp.Custom;
using System.Text.RegularExpressions;
using Gtk;
namespace MonitoringApp.Code.App
{
    public class Configuration
    {

        private static bool isLoadFirst = false;
        private static List<MyConfig> configLst;
        public static List<MyConfig> ConfigLst
        {
            get
            {
                if (configLst == null)
                {
                    try
                    {
                        if (!isLoadFirst)
                            return LoadFromInitParams();
                        else
                            return null;
                    }
                    catch (Exception ex)
                    {
                            LogManager.WriteErrorLog(ex);

                        return null;
                    }
                }
                return configLst;
            }
            set { configLst = value; }
        }

        /// <summary>
        /// Load Configuration file
        /// </summary>
        /// <returns></returns>
        private static List<MyConfig> LoadFromInitParams()
        {
            isLoadFirst = true;
            string _configPath = Path.Combine(Directory.GetCurrentDirectory(), "Configuration.txt");
            if (File.Exists(_configPath))
            {
                if (ConfigLst == null)
                    ConfigLst = new List<MyConfig>();
                else
                    return ConfigLst;
                using (StreamReader sr = new StreamReader(_configPath))
                {
                    int lineIndex = 1;
                    while (sr.Peek() > 0)
                    {
                        string str = sr.ReadLine().Trim();
                        if (str.Length == 0)
                            continue;
                        if (!str.Contains("[") || !str.Contains("]"))
                        {
                            LogManager.WriteErrorLog(string.Format("Config Error:'[' OR ']' Not Exist.At Line {0}.", lineIndex));
                            continue;
                        }
                        if (!str.Contains(":"))
                        {
                            LogManager.WriteErrorLog(string.Format("Config Error:':' Not Exist.At Line {0}.", lineIndex));
                            continue;
                        }
                        string[] names = str.Split(':');
                        str = str.Substring(str.IndexOf(':') + 1).Trim(']').Trim('[').Trim('\'');
                        string[] strConfigs = str.Split(',');
                        SetConfig(names, ConfigLst, strConfigs, lineIndex == 1);
                        lineIndex++;
                    }
                }
                return ConfigLst;
            }
            else
            {
                LogManager.WriteErrorLog(string.Format("can't find config file.Path:{0}.",_configPath));
                return null;
            }
        }
        /// <summary>
        /// Set Config
        /// </summary>
        /// <param name="name"></param>
        /// <param name="lst"></param>
        /// <param name="strConfigs"></param>
        private static void SetConfig(string[] name, List<MyConfig> lst, string[] strConfigs, bool isLineOne)
        {
            try
            {
                var mcConfig = (MonitoringConfigurations)Enum.Parse(typeof(MonitoringConfigurations), name[0], true);
                //Set Values
                for (int i = 0; i < strConfigs.Length; i++)
                {
                    string value = strConfigs[i].Trim('\'');
                    switch (mcConfig)
                    {
                        case MonitoringConfigurations.MonitoringDirectoryType:
                            {
                                #region MonitoringDirectoryType Defalut:immediate
                                switch (value.ToLower())
                                {
                                    case "immediate":
                                        {
                                            if (isLineOne)
                                            {
                                                MyConfig myConfig = new MyConfig();
                                                myConfig.MDType = MonitoringDirectoryType.Immediate;
                                                lst.Add(myConfig);
                                            }
                                            else
                                            {
                                                lst[i].MDType = MonitoringDirectoryType.Immediate;
                                            }
                                            break;
                                        }
                                    case "cycle":
                                        {
                                            if (isLineOne)
                                            {
                                                MyConfig myConfig = new MyConfig();
                                                myConfig.MDType = MonitoringDirectoryType.Cycle;
                                                lst.Add(myConfig);
                                            }
                                            else
                                            {
                                                lst[i].MDType = MonitoringDirectoryType.Cycle;
                                            }
                                            break;
                                        }
                                    default:
                                        {
                                            if (isLineOne)
                                            {
                                                MyConfig myConfig = new MyConfig();
                                                myConfig.MDType = MonitoringDirectoryType.Immediate;
                                                lst.Add(myConfig);
                                            }
                                            else
                                            {
                                                lst[i].MDType = MonitoringDirectoryType.Immediate;
                                            }
                                            break;
                                        }
                                }
                                #endregion
                                break;
                            }
                        case MonitoringConfigurations.Path:
                            #region Path
                            if (isLineOne)
                            {
                                MyConfig myConfig = new MyConfig();
                                myConfig.Path = value;
                                lst.Add(myConfig);
                            }
                            else
                            {
                                lst[i].Path = value;
                            }
                            #endregion
                            break;
                        case MonitoringConfigurations.IncludeSubdirectories:
                            #region IncludeSubdirectories
                            if (isLineOne)
                            {
                                MyConfig myConfig = new MyConfig();
                                myConfig.IncludeSubdirectories = Convert.ToBoolean(value);
                                lst.Add(myConfig);
                            }
                            else
                            {
                                lst[i].IncludeSubdirectories = Convert.ToBoolean(value);
                            }
                            #endregion
                            break;
                        case MonitoringConfigurations.Filter:
                            #region Filter
                            if (isLineOne)
                            {
                                MyConfig myConfig = new MyConfig();
                                myConfig.Filter = value;
                                lst.Add(myConfig);
                            }
                            else
                            {
                                lst[i].Filter = value;
                            }
                            break;
                            #endregion
                        case MonitoringConfigurations.BackupPath:
                            #region BackupPath
                            if (isLineOne)
                            {
                                MyConfig myConfig = new MyConfig();
                                myConfig.BackupPath = value;
                                lst.Add(myConfig);
                            }
                            else
                            {
                                lst[i].BackupPath = value;
                            }
                            #endregion
                            break;
                        case MonitoringConfigurations.TargetPath:
                            #region TargetPath
                            if (isLineOne)
                            {
                                MyConfig myConfig = new MyConfig();
                                myConfig.TargetPath = value;
                                lst.Add(myConfig);
                            }
                            else
                            {
                                lst[i].TargetPath = value;
                            }
                            #endregion
                            break;
                        case MonitoringConfigurations.BackupExpired:
                            #region BackupExpired  Unit:days  Default:30
                            if (isLineOne)
                            {
                                MyConfig myConfig = new MyConfig();
                                myConfig.BackupExpired = Convert.ToInt32(value.Length == 0 ? "30" : value);
                                lst.Add(myConfig);
                            }
                            else
                            {
                                lst[i].BackupExpired = Convert.ToInt32(value.Length == 0 ? "30" : value);
                            }
                            #endregion
                            break;
                        case MonitoringConfigurations.CycleMinutes:
                            #region CycleMinutes  Unit:Minute  Default:60
                            if (isLineOne)
                            {
                                MyConfig myConfig = new MyConfig();
                                myConfig.CycleMinutes = Convert.ToInt32(value.Length == 0 ? "60" : value);
                                lst.Add(myConfig);
                            }
                            else
                            {
                                lst[i].CycleMinutes = Convert.ToInt32(value.Length == 0 ? "60" : value);
                            }
                            #endregion
                            break;
                        default:
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.WriteErrorLog(ex);
            }


        }

    }
}

 

 

值得注意的是:

  1. 这里是按行读取的。从读取配置来看,可以看出,是支持多个配置项的。
  2. 如果出错,会记录日志。
  3. 和客户讲解如何配置是一件麻烦的事情。相关配置解释如下:
	MonitoringDirectoryType:目录类型,仅支持两个值(Immediate、Cycle)。Immediate表示即时监控(默认值),Cycle表示周期监控。	
	Path:监控目录路径。必须是存在的路径。
	TargetPath:目标目录路径。可以是远程目录路径。不能使用SMB路径,而应该是用如“/Volumes/mes_data/n81a”的类型。
	IncludeSubdirectories:是否涵盖子目录。
	Filter:过滤字符串。如“*”表示监控所有文件,“*.txt”表示监控所有的文本文件。
	BackupPath:备份路径。
	BackupExpired:备份过期时间。单位是天。必须为整数。默认值30天。
	CycleMinutes:周期循环时间。单位是分。 必须为整数。默认值60分钟。

 

然后针对配置写个说明文档,这样客户就会配置了。

2)记录日志

程序运行起来总不可避免的会遇到各种问题,记录日志就不可避免了。相关代码如下:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Gtk;

namespace MonitoringApp.Code.App
{
    public class LogManager
    {
        public static object obj = new object();
        static LogManager()
        {
        }
        #region Fields and Properties
        private static string _logPath = string.Empty;
        public static string LogPath
        {
            get
            {
                lock (obj)
                {
                    if (_logPath == string.Empty)
                    {
                        var _logStr = string.Format("{0}/log/{1}/{2}", Path.Combine(Directory.GetCurrentDirectory(), "Data"), DateTime.Now.ToString("yyyy-MM"), DateTime.Now.Day);
                        if (!System.IO.Directory.Exists(_logStr))
                            System.IO.Directory.CreateDirectory(_logStr);
                        return string.Format("{0}/", _logStr);
                    }
                    return _logPath;
                }
            }
            set { _logPath = value; }
        }
        private static string _logFielPrefix = string.Empty;
        public static string LogFielPrefix
        {
            get { return _logFielPrefix; }
            set { _logFielPrefix = value; }
        }
        #endregion

        #region Log

        public static void WriteLog(string logFile, string msg)
        {
            try
            {
                lock (obj)
                {
                    var _sb = new System.Text.StringBuilder();
                    _sb.Append(LogPath).Append(LogFielPrefix).Append(logFile).Append(".Log");
                    using (var _sw = System.IO.File.AppendText(_sb.ToString()))
                    {
                        _sw.WriteLine("==============================={0}===============================", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                        _sw.WriteLine(msg);
                        _sw.Flush();
                        _sw.Close();
                        Console.WriteLine(msg);

                    }
                }
            }
            catch
            { }
        }

        public static void WriteLog(LogFile logFile, string msg)
        {
            WriteLog(logFile.ToString(), msg);
        }
        public static void WriteTraceLog(string msg)
        {
            Console.WriteLine(msg);
        }

        public static void WriteErrorLog(string msg)
        {
            WriteLog(LogFile.Error, msg);
        }
        public static void WriteErrorLog(Exception ex)
        {
            var _sbError = new StringBuilder();
            _sbError.Append("[Message]").Append(ex.Message);
            _sbError.Append("\r\n[TargetSite]").Append(ex.TargetSite);
            _sbError.Append("\r\n[StackTrace]").Append(ex.StackTrace);
            _sbError.Append("\r\n[Source]").Append(ex.Source);
            foreach (var _item in ex.Data.Keys)
            {
                _sbError.Append("\r\n[").Append(_item).Append("]").Append(ex.Data[_item]);
            }
            if (ex.InnerException != null && ex.InnerException.Message != ex.Message)
            {
                _sbError.AppendLine("____________________________________________________________________________________");
                _sbError.Append("[Message]").Append(ex.InnerException.Message);
                _sbError.Append("\r\n[TargetSite]").Append(ex.InnerException.TargetSite);
                _sbError.Append("\r\n[StackTrace]").Append(ex.InnerException.StackTrace);
                _sbError.Append("\r\n[Source]").Append(ex.InnerException.Source);
                _sbError.AppendLine("____________________________________________________________________________________");
            }
            WriteLog(LogFile.Error, _sbError.ToString());
        }
        public static void WriteWarningLog(string msg)
        {
            WriteLog(LogFile.Warning, msg);
        }
        #endregion
    }

    public enum LogFile
    {
        Trace,
        Warning,
        Error,
        SQL,
        System
    }
}

值得注意的是“Directory.GetCurrentDirectory()可以获取到当前用户的个人目录,至于获取到程序当前目录路径,Winform的那一套不管用(如果哪位朋友找到了适合的方法,请留言)。苹果系统和Window系统差别太大,从没玩过苹果系统,刚开始玩还挺不习惯的。

接下来,讲述如何监控目录以及定时备份,最后讲述如何发布部署。发布部署才是最重要的一环。不上生产线,就不知道会有什么问题。当初以为这个小程序,一天就能搞定,结果中秋3天都废了。还好万幸搞定。时间关系,就此打住。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
4月前
|
存储 监控 数据库
Django 后端架构开发:高效日志规范与实践
Django 后端架构开发:高效日志规范与实践
77 1
|
2月前
|
Rust 前端开发 JavaScript
Tauri 开发实践 — Tauri 日志记录功能开发
本文介绍了如何为 Tauri 应用配置日志记录。Tauri 是一个利用 Web 技术构建桌面应用的框架。文章详细说明了如何在 Rust 和 JavaScript 代码中设置和集成日志记录,并控制日志输出。通过添加 `log` crate 和 Tauri 日志插件,可以轻松实现多平台日志记录,包括控制台输出、Webview 控制台和日志文件。文章还展示了如何调整日志级别以优化输出内容。配置完成后,日志记录功能将显著提升开发体验和程序稳定性。
99 1
Tauri 开发实践 — Tauri 日志记录功能开发
|
4月前
|
SQL 关系型数据库 MySQL
【MySQL】根据binlog日志获取回滚sql的一个开发思路
【MySQL】根据binlog日志获取回滚sql的一个开发思路
|
29天前
|
监控 开发者
鸿蒙5.0版开发:使用HiLog打印日志(ArkTS)
在HarmonyOS 5.0中,HiLog是系统提供的日志系统,支持DEBUG、INFO、WARN、ERROR、FATAL五种日志级别。本文介绍如何在ArkTS中使用HiLog打印日志,并提供示例代码。通过合理使用HiLog,开发者可以更好地调试和监控应用。
79 16
|
2月前
|
开发框架 缓存 安全
开发日志:IIS安全配置
开发日志:IIS安全配置
开发日志:IIS安全配置
|
2月前
|
开发工具 git
git显示开发日志+WinSW——将.exe文件注册为服务的一个工具+图床PicGo+kubeconfig 多个集群配置 如何切换
git显示开发日志+WinSW——将.exe文件注册为服务的一个工具+图床PicGo+kubeconfig 多个集群配置 如何切换
39 1
|
2月前
|
Linux C语言 iOS开发
MacOS环境-手写操作系统-06-在mac下通过交叉编译:C语言结合汇编
MacOS环境-手写操作系统-06-在mac下通过交叉编译:C语言结合汇编
27 0
|
4月前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
151 1
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
|
4月前
|
小程序 前端开发 API
微信小程序全栈开发中的异常处理与日志记录是一个重要而复杂的问题。
微信小程序作为业务拓展的新渠道,其全栈开发涉及前端与后端的紧密配合。本文聚焦小程序开发中的异常处理与日志记录,从前端的网络、页面跳转等异常,到后端的数据库、API调用等问题,详述了如何利用try-catch及日志框架进行有效管理。同时强调了集中式日志管理的重要性,并提醒开发者注意安全性、性能及团队协作等方面,以构建稳定可靠的小程序应用。
72 1
|
4月前
|
人工智能 Java Spring
Spring框架下,如何让你的日志管理像‘AI’一样智能,提升开发效率的秘密武器!
【8月更文挑战第31天】日志管理在软件开发中至关重要,不仅能帮助开发者追踪问题和调试程序,还是系统监控和运维的重要工具。在Spring框架下,通过合理配置Logback等日志框架,可大幅提升日志管理效率。本文将介绍如何引入日志框架、配置日志级别、在代码中使用Logger,以及利用ELK等工具进行日志聚合和分析,帮助你构建高效、可靠的日志管理系统,为开发和运维提供支持。
74 0