You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

494 lines
18 KiB
C#

9 months ago
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<LogParameterInfo>();
}
/// <summary>
/// 队列名称
/// </summary>
[RequiredParameter]
public string RepoName { get; set; }
/// <summary>
/// 授权信息
/// </summary>
[RequiredParameter]
public string Authorization { get; set; }
/// <summary>
/// 请求地址
/// </summary>
[RequiredParameter]
public string ServerAddress { get; set; }
/// <summary>
/// 参数
/// </summary>
[ArrayParameter(typeof(LogParameterInfo), "parameter")]
public IList<LogParameterInfo> 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;
}
/// <summary>
/// SignRequest signs the request in the algorithm of Pandora
/// see doc here at
/// </summary>
/// <param name="url"></param>
/// <param name="method"></param>
/// <param name="headers">
/// 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-
/// </param>
/// <param name="qiniuSubResource"></param>
/// <returns></returns>
public string SignRequest(string url, string method, Dictionary<string, string> headers)
{
Dictionary<string, object> tokenDesc = new Dictionary<string, object>();
//filter the qiniu heades
List<string> qiniuHeaderKeys = new List<string>();
foreach (string key in headers.Keys)
{
if (key.StartsWith("X-Qiniu-"))
{
qiniuHeaderKeys.Add(key);
}
}
qiniuHeaderKeys.Sort();
string canHeadersStr = null;
if (qiniuHeaderKeys.Count > 0)
{
List<string> canHeaders = new List<string>();
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());
}
}
}