前言

接着异常七后,因为以前看过盛派这块代码,正好重新整理一下。

正文

BaseException

首先看下BaseException 类:

继承:public class BaseException : ApplicationException

这个ApplicationException 前文中提及到,文档地址:https://docs.microsoft.com/zh-cn/dotnet/api/system.applicationexception?view=netcore-3.1

这里面有一个问题就是文档里提示的是不应使用Application,应该使用Exception。

网上别人给的不建议使用的说法是:

如果设计的应用程序需要创建自己的异常,则建议从Exception类派生自定义异常。最初认为自定义异常应该来自ApplicationException类; 然而在实践中,这并没有被发现增加显着价值。

好的,那么来看下其实例方法。

/// <summary>
/// BaseException
/// </summary>
/// <param name="message">异常消息</param>
/// <param name="inner">内部异常信息</param>
/// <param name="logged">是否已经使用WeixinTrace记录日志,如果没有,BaseException会进行概要记录</param>
public BaseException(string message, Exception inner, bool logged = false)
: base(message, inner)
{
if (!logged)
{
SenparcTrace.BaseExceptionLog(this);
}
}

那么看下BaseExceptionLog干了什么吧。

/// <summary>
/// BaseException 日志
/// </summary>
/// <param name="ex"></param>
public static void BaseExceptionLog(Exception ex)
{
BaseExceptionLog(new BaseException(ex.Message, ex, false));
} /// <summary>
/// BaseException 日志
/// </summary>
/// <param name="ex"></param>
public static void BaseExceptionLog(BaseException ex)
{
if (Config.IsDebug)
{
using (SenparcTraceItem senparcTraceItem = new SenparcTraceItem(_logEndActon, "BaseException", null))
{
senparcTraceItem.Log(ex.GetType().Name);
senparcTraceItem.Log("Message:{0}", ex.Message);
senparcTraceItem.Log("StackTrace:{0}", ex.StackTrace);
if (ex.InnerException != null)
{
senparcTraceItem.Log("InnerException:{0}", ex.InnerException.Message);
senparcTraceItem.Log("InnerException.StackTrace:{0}", ex.InnerException.StackTrace);
}
if (OnBaseExceptionFunc != null)
{
try
{
OnBaseExceptionFunc(ex);
}
catch
{
}
}
}
}
}

上面的大体内容是,创建了一个SenparcTraceItem 的实体类,值得注意的是SenparcTraceItem 使用了using。

证明了什么呢?证明了SenparcTraceItem 是一个非托管,那么自己实现了回收机制,可查看我的非托管程序里面。

senparcTraceItem.Log 做了什么呢?

public void Log(string messageFormat, params object[] param)
{
Log(messageFormat.FormatWith(param));
} public void Log(string message)
{
if (Content != null)
{
Content += Environment.NewLine;
}
Content = Content + "\t" + message;
}

只是做一些字符拼接,那么问题来了,它是如何写道持久化文件中的呢?

public void Dispose()
{
_logEndAction?.Invoke(this);
}

当其回收的时候会触发_logEndAction,那么这个_logEndAction委托做啥呢?这个好像是我们传进去的吧,找到我们穿进去的值。

/// <summary>
/// 结束日志记录
/// </summary>
protected static Action<SenparcTraceItem> _logEndActon = delegate(SenparcTraceItem traceItem)
{
string logStr2 = traceItem.GetFullLog();
SenparcMessageQueue senparcMessageQueue = new SenparcMessageQueue();
string str = SystemTime.Now.Ticks.ToString();
int num = traceItem.ThreadId;
string str2 = num.ToString();
num = logStr2.Length;
string key = str + str2 + num.ToString();
senparcMessageQueue.Add(key, delegate
{
_queue(logStr2);
});
};

逻辑就是GetFullLog:

/// <summary>
/// 获取完整单条日志的字符串信息
/// </summary>
public string GetFullLog()
{
return string.Format("[[[{0}]]]\r\n[{1}]\r\n[线程:{2}]\r\n{3}\r\n\r\n", Title, DateTime.ToString("yyyy/MM/dd HH:mm:ss.ffff"), ThreadId, Content);
}

然后加入到队列中:

SenparcMessageQueue senparcMessageQueue = new SenparcMessageQueue();
senparcMessageQueue.Add(key, delegate{_queue(logStr2);});

它的一个队列设计是这样的:

将其加在一个字典中:

public SenparcMessageQueueItem Add(string key, Action action)
{
lock (MessageQueueSyncLock)
{
SenparcMessageQueueItem senparcMessageQueueItem = new SenparcMessageQueueItem(key, action, null);
MessageQueueDictionary.TryAdd(key, senparcMessageQueueItem);
return senparcMessageQueueItem;
}
}

自定义字典:

public static MessageQueueDictionary MessageQueueDictionary = new MessageQueueDictionary();

它的消费函数在另一个线程中,这里就不介绍了。

值得关心的是_queue,毕竟我们要知道我们的log打印到了什么地方:

/// <summary>
/// 队列执行逻辑
/// </summary>
protected static Action<string> _queue = async delegate(string logStr)
{
IBaseObjectCacheStrategy cache = Cache;
TimeSpan retryDelay = default(TimeSpan);
using (await cache.BeginCacheLockAsync("SenparcTraceLock", "", 0, retryDelay))
{
string text = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Data", "SenparcTraceLog");
if (!Directory.Exists(text))
{
Directory.CreateDirectory(text);
}
string text2 = Path.Combine(text, string.Format("SenparcTrace-{0}.log", SystemTime.Now.ToString("yyyyMMdd")));
if (AutoUnlockLogFile)
{
for (int i = 0; i < 3; i++)
{
if (!FileHelper.FileInUse(text2))
{
break;
}
GC.Collect();
GC.WaitForPendingFinalizers();
DateTimeOffset now = SystemTime.Now;
if (i < 2)
{
do
{
retryDelay = SystemTime.NowDiff(now);
}
while (retryDelay.TotalMilliseconds < 100.0);
}
}
}
try
{
using (FileStream fs = new FileStream(text2, FileMode.OpenOrCreate))
{
using (StreamWriter sw = new StreamWriter(fs))
{
fs.Seek(0L, SeekOrigin.End);
await sw.WriteAsync(logStr);
await sw.FlushAsync();
}
}
}
catch (Exception)
{
}
if (OnLogFunc != null)
{
try
{
OnLogFunc();
}
catch
{
}
}
}
};

根据上述中,可得:保存在App_Data/SenparcTraceLog目录下。

好的那么来看BaseException 的子类吧。

WeixinException

public class WeixinException : BaseException

看下它的实例化:

/// <summary>
/// WeixinException
/// </summary>
/// <param name="message">异常消息</param>
/// <param name="inner">内部异常信息</param>
/// <param name="logged">是否已经使用WeixinTrace记录日志,如果没有,WeixinException会进行概要记录</param>
public WeixinException(string message, Exception inner, bool logged = false)
: base(message, inner, true/* 标记为日志已记录 */)
{
if (!logged)
{
//WeixinTrace.Log(string.Format("WeixinException({0}):{1}", this.GetType().Name, message)); WeixinTrace.WeixinExceptionLog(this);
}
}

他首先干的是就是让它的基类不答应log,交给它自己处理。

WeixinTrace 实际上继承SenparcTrace,这里可以猜测到基本就是在SenparcTrace封装一层了。

public class WeixinTrace : SenparcTrace

实际上不出所料:

/// <summary>
/// WeixinException 日志
/// </summary>
/// <param name="ex"></param>
public static void WeixinExceptionLog(WeixinException ex)
{
if (!Config.IsDebug)
{
return;
}
using (var traceItem = new SenparcTraceItem(SenparcTrace._logEndActon, "WeixinException"))
{
traceItem.Log(ex.GetType().Name);
traceItem.Log("AccessTokenOrAppId:{0}", ex.AccessTokenOrAppId);
traceItem.Log("Message:{0}", ex.Message);
traceItem.Log("StackTrace:{0}", ex.StackTrace);
if (ex.InnerException != null)
{
traceItem.Log("InnerException:{0}", ex.InnerException.Message);
traceItem.Log("InnerException.StackTrace:{0}", ex.InnerException.StackTrace);
}
} if (OnWeixinExceptionFunc != null)
{
try
{
OnWeixinExceptionFunc(ex);
}
catch
{
}
}
}

上文只是一个简单的源码查看,如需查看源码,可以去github搜索senparc,是一个集成小程序和公众号的框架,个人开发小程序的时候只是简单的看了下。

最新文章

  1. cocos2d-x 帧循环不严谨造成场景切换卡顿
  2. JNI输出log信息
  3. eclipse闪退
  4. 20145305 《Java程序设计》第3周学习总结
  5. 关于JFace带复选框的树
  6. 开放Nginx在文件夹列表功能
  7. php生成PDF文件(FPDF)
  8. Fiddler屏蔽某些url的抓取方法
  9. Django里使用open函数
  10. SmartCode 正式开源,不只是代码生成器!
  11. spring aspect获取抽象基类日志
  12. Vue中的slot内容分发
  13. 使用netstat命令查看端口的使用情况
  14. tensorflow 导入gfile模型文件
  15. P2153 [SDOI2009]晨跑
  16. windows下如何查看端口,关闭端口,开启端口
  17. [转帖]第二个显示屏上禁用Windows任务栏
  18. Fantacy团队第一次站立会议
  19. 初识构建工具-gradle
  20. Pl/SQl 安装和配置Oracle 数据库连接

热门文章

  1. JVM系列之:String.intern的性能
  2. PHP date_timestamp_set() 函数
  3. PHP preg_last_error() 函数
  4. Skill 计算两点距离
  5. HDU Typewriter 6583 dp SAM 卡常
  6. luogu P4769 [NOI2018]冒泡排序 结论 树状数组 卡特兰数
  7. K近邻算法(二)
  8. “随手记”开发记录day10
  9. TF签名 外部测试 内部测试 TestFlight
  10. JS 留言板案例