using NLog; using NLog.Config; using NLog.Targets; using NLog.Targets.Wrappers; using System; using System.IO; using Common.Logging; using System.Net; using System.Threading.Tasks; using System.Text; using System.Linq; using NLog.Layouts; using System.Collections.Generic; using Newtonsoft.Json; using NLog.RestTarget; using NLog.Common; using System.Diagnostics; using POSV.Utils; using System.Security.Cryptography; using POSV; using System.Windows.Forms; using POSV.Common.Util; namespace POSV.Utils { public static class NLogUtils { private static object locker = new object(); static NLogUtils() { string dataDirFullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory , @"data/backup/"); if (!Directory.Exists(dataDirFullPath)) { lock (locker) { if (!Directory.Exists(dataDirFullPath)) { Directory.CreateDirectory(dataDirFullPath); } } } string logDirFullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory , @"logs/"); if (!Directory.Exists(logDirFullPath)) { lock (locker) { if (!Directory.Exists(logDirFullPath)) { Directory.CreateDirectory(logDirFullPath); } } } } //zhangy 2020-02-19 Edit 修改日志文件输出格式,添加按日归档、保留7日模式 static void nlog_to_file_and_archive(LoggingConfiguration config) { var fileTarget = new FileTarget { MaxArchiveFiles = 7, FileName = "${basedir}/logs/log.txt" , Layout = Layout.FromString("${longdate} | [${uppercase:${level}}] | ${logger} | ${message} | ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}") , ArchiveFileName = "${basedir}/logs/archives/log${shortdate}.{#####}.txt", ArchiveEvery = FileArchivePeriod.Day, ArchiveNumbering = ArchiveNumberingMode.Rolling, EnableArchiveFileCompression = true, ConcurrentWrites = true, KeepFileOpen = false, AutoFlush = true, DeleteOldFileOnStartup = false, CreateDirs = true, }; AsyncTargetWrapper wrapper = new AsyncTargetWrapper(); wrapper.WrappedTarget = fileTarget; wrapper.QueueLimit = 5000; wrapper.OverflowAction = AsyncTargetWrapperOverflowAction.Discard; // Adding "File" as one of the log targets config.AddTarget("file" , wrapper); config.LoggingRules.Add(new NLog.Config.LoggingRule("*" , NLog.LogLevel.Info , wrapper)); } static void nlog_to_console(LoggingConfiguration config) { var consoleTarget = new ColoredConsoleTarget { Layout = Layout.FromString("${longdate} | [${uppercase:${level}}] | ${logger} | ${message} | ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}") }; AsyncTargetWrapper wrapper = new AsyncTargetWrapper(); wrapper.WrappedTarget = consoleTarget; wrapper.QueueLimit = 5000; wrapper.OverflowAction = AsyncTargetWrapperOverflowAction.Discard; config.AddTarget("console" , wrapper); config.LoggingRules.Add(new LoggingRule("*" , NLog.LogLevel.Info , wrapper)); } public static void InitLogger() { try { NLog.LogManager.ThrowExceptions = true; var config = new LoggingConfiguration(); nlog_to_console(config); nlog_to_file_and_archive(config); NLog.LogManager.Configuration = config; CommonLoggingAdapter.AdapterLogger(); } catch (Exception ex) { ExceptionUtils.Current.Handle(ex); } } } } namespace NLog.RestTarget { [Target("QiNiuLogService")] public sealed class QiNiuLogTarget : TargetWithLayout { public QiNiuLogTarget() { RepoName = string.Empty; Authorization = string.Empty; ServerAddress = string.Empty; Parameters = new List(); } /// /// 队列名称 /// [RequiredParameter] public string RepoName { get; set; } /// /// 授权信息 /// [RequiredParameter] public string Authorization { get; set; } /// /// 请求地址 /// [RequiredParameter] public string ServerAddress { get; set; } /// /// 参数 /// [ArrayParameter(typeof(LogParameterInfo), "parameter")] public IList Parameters { get; private set; } private LayoutWithHeaderAndFooter LHF { get => (LayoutWithHeaderAndFooter)base.Layout; set => base.Layout = value; } public override Layout Layout { get => LHF.Layout; set { if (value is LayoutWithHeaderAndFooter) { base.Layout = value; } else if (LHF == null) { LHF = new LayoutWithHeaderAndFooter() { Layout = value }; } else { LHF.Layout = value; } } } protected override void Write(AsyncLogEventInfo[] logEvents) { bool isUploadToQiniu = Global.Instance.GlobalConfigBoolValue(ConfigConstant.LOG_UPLOAD_TO_QINIU, false); Console.WriteLine(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + isUploadToQiniu); if (isUploadToQiniu) { SendTheMessageToRemoteHost(logEvents); } } private void SendTheMessageToRemoteHost(AsyncLogEventInfo[] logEvents) { try { foreach (var logEvent in logEvents) { var uri = new Uri(this.ServerAddress); var eventInfo = logEvent.LogEvent; //WiFi网络仅仅上传Error级别的消息 if (Global.Instance.IsWiFi) { if (eventInfo.Level != LogLevel.Error || eventInfo.Level != LogLevel.Fatal) { continue; } } var tenantNo = Global.Instance.Authc != null ? Global.Instance.Authc.TenantId : "000000"; var storeId = Global.Instance.Authc != null ? Global.Instance.Authc.StoreId : "000000000000000000"; var storeNo = Global.Instance.Authc != null ? Global.Instance.Authc.StoreNo : "000000"; var storeName = Global.Instance.Authc != null ? Global.Instance.Authc.StoreName : ""; var posId = Global.Instance.Authc != null ? Global.Instance.Authc.PosId : "000000000000000000"; var posNo = Global.Instance.Authc != null ? Global.Instance.Authc.PosNo : "000000"; Parameters.Clear(); Parameters.Add(new LogParameterInfo() { Name = "appsign", Layout = Constant.APP_SIGN }); Parameters.Add(new LogParameterInfo() { Name = "version", Layout = Application.ProductVersion }); var theme = Global.Instance.GlobalConfigStringValue(ConfigConstant.LAYOUT_THEME, ThemeEnum.快餐.ToString()); Parameters.Add(new LogParameterInfo() { Name = "layout", Layout = theme }); Parameters.Add(new LogParameterInfo() { Name = "tenantNo", Layout = tenantNo }); Parameters.Add(new LogParameterInfo() { Name = "storeId", Layout = storeId }); Parameters.Add(new LogParameterInfo() { Name = "storeNo", Layout = storeNo }); Parameters.Add(new LogParameterInfo() { Name = "storeName", Layout = storeName }); Parameters.Add(new LogParameterInfo() { Name = "posId", Layout = posId }); Parameters.Add(new LogParameterInfo() { Name = "posNo", Layout = posNo }); Parameters.Add(new LogParameterInfo() { Name = "sequenceId", Layout = eventInfo.SequenceID }); Parameters.Add(new LogParameterInfo() { Name = "message", Layout = eventInfo.FormattedMessage }); Parameters.Add(new LogParameterInfo() { Name = "level", Layout = eventInfo.Level.Name }); Parameters.Add(new LogParameterInfo() { Name = "loggerName", Layout = eventInfo.LoggerName }); Parameters.Add(new LogParameterInfo() { Name = "loggerDate", Layout = eventInfo.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss") }); string errorMessage = string.Empty; var exception = eventInfo.Exception; if (exception != null) { errorMessage = GetExceptionInfo(exception); } Parameters.Add(new LogParameterInfo() { Name = "exception", Layout = errorMessage }); StringBuilder stringBuilder = new StringBuilder(); foreach (var item in Parameters) { stringBuilder.Append($"{item.Name}={item.Layout}\t"); } string message = stringBuilder.ToString().Replace("\r", "\\r").Replace("\n", "\\n"); ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; using (var client = new ExpectContinueAware()) { Console.WriteLine(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"+Encoding.UTF8.GetByteCount(string.Concat(message, "\n"))); client.Headers.Add("Content-Type", "text/plain"); client.Headers.Add("Authorization", this.Authorization); client.Encoding = Encoding.UTF8; client.UploadStringCompleted += (sender, e) => { }; client.UploadStringAsync(uri, "POST", string.Concat(message,"\n")); } } } catch (Exception ex) { ExceptionUtils.Current.Handle(ex); } } private string GetExceptionInfo(Exception e) { string errorMessage = e.Message + " " + e.StackTrace; if (e.InnerException != null) { errorMessage += e.InnerException.Message + " " + e.InnerException.StackTrace; if (e.InnerException.InnerException != null) { errorMessage += e.InnerException.InnerException.Message + " " + e.InnerException.InnerException.StackTrace; } } return errorMessage; } } public class ExpectContinueAware : System.Net.WebClient { protected override System.Net.WebRequest GetWebRequest(Uri address) { System.Net.WebRequest request = base.GetWebRequest(address); if (request is System.Net.HttpWebRequest) { var hwr = request as System.Net.HttpWebRequest; hwr.ServicePoint.Expect100Continue = false; } return request; } } public class Auth { public const string ContentType = "Content-Type"; public const string ContentMD5 = "Content-MD5"; public const string Date = "Date"; public const string Authorization = "Authorization"; private string accessKey; private string secretKey; public Auth(string accessKey, string secretKey) { this.accessKey = accessKey; this.secretKey = secretKey; } /// /// SignRequest signs the request in the algorithm of Pandora /// see doc here at /// /// /// /// /// method - request method /// resource - request path /// expires - deadline in unix timestamp in seconds /// contentType - content type /// contentMD5 - content md5, optional /// headers - sorted headers whose keys start with X-Qiniu- /// /// /// public string SignRequest(string url, string method, Dictionary headers) { Dictionary tokenDesc = new Dictionary(); //filter the qiniu heades List qiniuHeaderKeys = new List(); foreach (string key in headers.Keys) { if (key.StartsWith("X-Qiniu-")) { qiniuHeaderKeys.Add(key); } } qiniuHeaderKeys.Sort(); string canHeadersStr = null; if (qiniuHeaderKeys.Count > 0) { List canHeaders = new List(); foreach (string key in qiniuHeaderKeys) { canHeaders.Add(String.Format("{0}:{1}", key.ToLower(), headers[key])); } canHeadersStr = String.Join("\n", canHeaders); } if (!String.IsNullOrEmpty(canHeadersStr)) { tokenDesc["headers"] = canHeadersStr; } //check other headers if (headers.ContainsKey(ContentType)) { tokenDesc["contentType"] = headers[ContentType]; } if (headers.ContainsKey(ContentMD5)) { tokenDesc["contentMD5"] = headers[ContentMD5]; } Uri reqURI = new Uri(url); tokenDesc["resource"] = reqURI.AbsolutePath; tokenDesc["method"] = method; tokenDesc["expires"] = GetUnixTimestampInSeconds() + 24 * 60 * 60 * 7; string tokenDescData = JsonConvert.SerializeObject(tokenDesc); return String.Format("Pandora {0}", this.SignWithData(tokenDescData)); } private string encodedSign(byte[] data) { HMACSHA1 hmac = new HMACSHA1(Encoding.UTF8.GetBytes(this.secretKey)); byte[] digest = hmac.ComputeHash(data); return UrlSafeBase64Encode(digest); } private string encodedSign(string str) { byte[] data = Encoding.UTF8.GetBytes(str); return encodedSign(data); } public string Sign(byte[] data) { return string.Format("{0}:{1}", this.accessKey, encodedSign(data)); } public string Sign(string str) { byte[] data = Encoding.UTF8.GetBytes(str); return Sign(data); } public string SignWithData(byte[] data) { string encodedData = UrlSafeBase64Encode(data); return string.Format("{0}:{1}:{2}", this.accessKey, encodedSign(encodedData), encodedData); } public string SignWithData(string str) { byte[] data = Encoding.UTF8.GetBytes(str); return SignWithData(data); } public static long GetUnixTimestampInSeconds() { System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); // current zone long timeStamp = (long)(DateTime.Now - startTime).TotalMilliseconds / 1000; // timestamp in seconds return timeStamp; } public static string CreateHttpDateTime(DateTime dateTime) { return dateTime.ToUniversalTime().ToString("r"); } public static string CreateRFC3339DateTime(DateTime dateTime) { return dateTime.ToString("yyyy-MM-dd'T'HH:mm:ss.fffzzz"); } public static DateTime FromRFC3339DateTime(string dateTimeStr) { return DateTime.Parse(dateTimeStr); } public static string UrlSafeBase64Encode(string text) { return UrlSafeBase64Encode(Encoding.UTF8.GetBytes(text)); } public static string UrlSafeBase64Encode(byte[] data) { return Convert.ToBase64String(data).Replace('+', '-').Replace('/', '_'); } public static string UrlSafeBase64Encode(string bucket, string key) { return UrlSafeBase64Encode(bucket + ":" + key); } public static byte[] UrlsafeBase64Decode(string text) { return Convert.FromBase64String(text.Replace('-', '+').Replace('_', '/')); } } public class LogParameterInfo { public string Name { get; set; } public object Layout { get; set; } public override bool Equals(object obj) { var o = obj as LogParameterInfo; return o != null && Name == o.Name; } public override int GetHashCode() { return 31 * 17 + ((this == null) ? -1 : base.GetHashCode()); } } }