Nlog适配达梦数据库进行日志插入
前言
原来使用的是SQLServer数据库,使用Nlog很流畅,没有什么问题。现在有个新项目需要使用麒麟操作系统和达梦数据库,业务流程开发完成之后发现Nlog配置文件中把数据库连接内容修改之后不能执行插入操作。
原Nlog.config配置
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"autoReload="true"internalLogLevel=" Debug" internalLogFile="path_to_your_internal_log_file.txt">throwExceptions="false"><targets><!--<target name="file" xsi:type="AsyncWrapper" queueLimit="5000" maxArchiveDays="7" maxArchiveFiles="7" overflowAction="Discard"><target xsi:type="File" fileName="${basedir}/Nlogs/${shortdate}.log" layout="${longdate} ${level:uppercase=true} ${event-context:item=Action} ${message} ${event-context:item=Amount} ${stacktrace}" /></target>--><target name="file" xsi:type="AsyncWrapper" queueLimit="5000" overflowAction="Discard" ><target xsi:type="File"fileName="${basedir}/Nlogs/${shortdate}.log"archiveFileName="${basedir}/Archive/${shortdate}.txt"layout="***${newline} | 日志时间:${longdate} | 级别:${level:uppercase=true}${newline} | 消息:${message}${newline} | 开始时间: ${mdlc:item=log-start-time} | 开始线程: ${mdlc:item=log-start-thread} | 方法:${callsite:className=true:fileName=true:includeSourcePath=false:methodName=true}${newline}***"archiveAboveSize="102400000"maxArchiveFiles="30"archiveEvery="Day"/></target><target xsi:type="Database"name="dbTarget"dbProvider="Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient"connectionString="TrustServerCertificate=True;Data Source=x.x.x.x;Initial Catalog=Logs;Persist Security Info=True;User ID=sa;Password=123456;"commandText="INSERT INTO [dbo].[Logs] ([LongDate] ,[Level] ,[MachineName], [ProcessName], [ProcessId] , [ThreadId] ,[Logger] ,[Message] ,[Exception], [UserName], [IP], LogStartTicks, LogStartThread, PollFlag) VALUES (@LongDate ,@Level ,@MachineName, @ProcessName, @ProcessId, @ThreadId ,@Logger ,@Message ,@Exception, @UserName, @IP, @LogStartTicks, @LogStartThread, @PollFlag)"><parameter name="@LongDate" layout="${date:format=yyyy-MM-dd HH\:mm\:ss.fff}" /><parameter name="@Level" layout="${level}" /><parameter name="@MachineName" layout="${machineName}" /><parameter name="@ProcessName" layout="${processname}" /><parameter name="@ProcessId" layout="${processid}" /><parameter name="@ThreadId" layout="${threadid}" /><parameter name="@Logger" layout="${logger}" /><parameter name="@Message" layout="${message}" /><parameter name="@Exception" layout="${exception:format=tostring}" /><parameter name="@UserName" layout="${aspnet-user-identity}" /><parameter name="@IP" layout="${aspnet-request:serverVariable=REMOTE_ADDR}" /><parameter name="@LogStartTicks" layout="${mdlc:item=log-start-time}" /><parameter name="@LogStartThread" layout="${mdlc:item=log-start-thread}" /><parameter name="@PollFlag" layout="${mdlc:item=log-poll-flag}" /></target></targets><rules><logger name="*" minlevel="Debug" writeTo="file" /><logger name="*" minlevel="Info" writeTo="file,dbTarget" /><logger name="*" minlevel="ERROR" writeTo="file,dbTarget,SendMail" /></rules></nlog>
将上面的数据库内容修改成达梦数据库的,不执行插入。查了较多资料也没查出来原因。(包都装完了,和包没关系)
实现
Nlog配置文件
<?xml version="1.0" encoding="utf-8"?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"autoReload="true"internalLogLevel="Debug"internalLogFile="B:\logs\nlog-internal.log"throwExceptions="false"><!-- 必须添加:注册包含DmDatabaseTarget的程序集 --><extensions><add assembly="GeneralWms.Application"/></extensions><targets><!-- 文件日志 --><target name="file" xsi:type="File"fileName="${basedir}/Nlogs/${shortdate}.log"archiveFileName="${basedir}/Archive/${shortdate}.txt"layout="***${newline} | 日志时间:${longdate} | 级别:${level:uppercase=true}${newline} | 消息:${message}${newline} | 开始时间: ${mdlc:item=log-start-time} | 开始线程: ${mdlc:item=log-start-thread} | 方法:${callsite:className=true:fileName=true:includeSourcePath=false:methodName=true}${newline}***"archiveAboveSize="102400000"maxArchiveFiles="30"archiveEvery="Day"/><!-- 同步写入数据库 --><target name="dmDb"type="~.DmDatabaseTarget, GeneralWms.Application"ConnectionString="Server=x.x.x.x;Database=DAMENG;User=SYSDBA;Password=123456;"includeCallSite="true"/></targets><rules><!--只写入文件目标--> <logger name="*" minlevel="Debug" writeTo="file" /><!--同时写入文件和数据库--> <logger name="*" minlevel="Info" writeTo="file,dmDb" /><!--错误及以上级别同时写入文件和数据库--> <logger name="*" minlevel="Error" writeTo="file,dmDb" /></rules><targets><target name="debug" type="Debug" layout="${longdate} ${level} ${message} ${exception}" /></targets>
</nlog>
新增增加类
[Target("DmDatabaseTarget")]public class DmDatabaseTarget : NLog.Targets.TargetWithContext{// 数据库连接字符串属性(可在NLog.config中配置)public string ConnectionString = "";//在这写死// 构造函数public DmDatabaseTarget(){// 默认包含调用站点信息this.IncludeCallSite = true;this.IncludeCallSiteStackTrace = true;}// 异步写入日志到数据库protected override void Write(LogEventInfo logEvent){//var logEvent = new LogEventInfo(LogLevel.Info, loggerName, "Your message here");//logEvent.Properties["LogStartTicks"] = someValue; // 设置 LogStartTicks 的值//logEvent.Properties["LogStartThread"] = Thread.CurrentThread.ManagedThreadId; // 设置 LogStartThread 的值if (string.IsNullOrEmpty(ConnectionString)){throw new InvalidOperationException("Connection string is null or empty.");}try{using (var conn = new DmConnection(ConnectionString)){conn.Open(); // 打开数据库连接using (var cmd = new DmCommand()){cmd.Connection = conn;cmd.CommandText = @"INSERT INTO LOGS (ID,LONGDATE, LEVEL, MACHINENAME, PROCESSNAME, PROCESSID, THREADID, LOGGER, MESSAGE, EXCEPTION, USERNAME, IP, LOGSTARTTICKS, LOGSTARTTHREAD, POLLFLAG) VALUES (:ID, :LONGDATE, :LEVEL, :MACHINENAME, :PROCESSNAME,:PROCESSID, :THREADID, :LOGGER, :MESSAGE,:EXCEPTION, :USERNAME, :IP, :LOGSTARTTICKS,:LOGSTARTTHREAD, :POLLFLAG)";var generator = new SnowflakeIdGenerator(0);// 使用实例调用 GenerateId 方法var snowflakeId = generator.GenerateId();// 设置日志开始时间和当前线程ID到 MDClong logStartTicks = DateTime.UtcNow.Ticks;int logStartThread = Thread.CurrentThread.ManagedThreadId;// 将这些值手动添加到 logEvent.PropertieslogEvent.Properties["LogStartTicks"] = logStartTicks;logEvent.Properties["LogStartThread"] = logStartThread;// 添加参数(达梦数据库使用:作为参数前缀)cmd.Parameters.Add(new DmParameter(":ID", snowflakeId));cmd.Parameters.Add(new DmParameter(":LONGDATE", logEvent.TimeStamp));cmd.Parameters.Add(new DmParameter(":LEVEL", logEvent.Level.ToString()));cmd.Parameters.Add(new DmParameter(":MACHINENAME", Environment.MachineName));cmd.Parameters.Add(new DmParameter(":PROCESSNAME", GetCurrentProcessName()));cmd.Parameters.Add(new DmParameter(":PROCESSID", GetCurrentProcessId()));cmd.Parameters.Add(new DmParameter(":THREADID", System.Threading.Thread.CurrentThread.ManagedThreadId));cmd.Parameters.Add(new DmParameter(":LOGGER", logEvent.LoggerName));cmd.Parameters.Add(new DmParameter(":MESSAGE", logEvent.FormattedMessage));cmd.Parameters.Add(new DmParameter(":EXCEPTION", logEvent.Exception?.ToString() ?? string.Empty));// 设置日志开始时间和当前线程ID到 MDC// 在开始记录日志之前,将值添加到 MDC//MappedDiagnosticsContext.Set("LogStartTicks", DateTime.UtcNow.Ticks.ToString());//MappedDiagnosticsContext.Set("LogStartThread", Thread.CurrentThread.ManagedThreadId.ToString());// 从日志属性中获取自定义字段logEvent.Properties.TryGetValue("UserName", out var userName);logEvent.Properties.TryGetValue("IP", out var ip);logEvent.Properties.TryGetValue("LogStartTicks", out var logStartTicksProperty);logEvent.Properties.TryGetValue("LogStartThread", out var logStartThreadProperty);logEvent.Properties.TryGetValue("PollFlag", out var pollFlag);cmd.Parameters.Add(new DmParameter(":USERNAME", userName ?? DBNull.Value));cmd.Parameters.Add(new DmParameter(":IP", ip ?? DBNull.Value));cmd.Parameters.Add(new DmParameter(":LOGSTARTTICKS", logStartTicksProperty ?? logStartTicks));cmd.Parameters.Add(new DmParameter(":LOGSTARTTHREAD", logStartThreadProperty ?? logStartThread));cmd.Parameters.Add(new DmParameter(":POLLFLAG", pollFlag ?? false));// 执行SQL命令cmd.ExecuteNonQuery();}}}catch (Exception ex){// 捕获异常并记录日志LogManager.GetCurrentClassLogger().Error(ex, $"写入数据库日志失败,日志内容:{logEvent.FormattedMessage}");}}// 辅助方法:获取当前进程名private static string GetCurrentProcessName(){try{return System.Diagnostics.Process.GetCurrentProcess().ProcessName;}catch{return "Unknown";}}// 辅助方法:获取当前进程IDprivate static int GetCurrentProcessId(){try{return System.Diagnostics.Process.GetCurrentProcess().Id;}catch{return -1;}}}
Program类
在Main方法中写
// 类型加载测试try{var type = Type.GetType("~.DmDatabaseTarget, GeneralWms.Application");if (type == null){throw new Exception("类型加载失败!可能原因:\n" +"1. 命名空间不匹配\n" +"2. 类不是 public\n" +"3. 程序集未正确引用");}Console.WriteLine("类型加载成功!");// 实例化测试var target = Activator.CreateInstance(type) as NLog.Targets.Target;Console.WriteLine(target != null ? "Target 实例化成功" : "Target 实例化失败");}catch (Exception ex){Console.WriteLine($"测试失败: {ex}");}//// 配置 NLogvar config = new LoggingConfiguration();// 使用反射加载自定义目标Type targetType = Type.GetType("~.DmDatabaseTarget, GeneralWms.Application");if (targetType != null){// 创建目标对象var target = (Target)Activator.CreateInstance(targetType);target.Name = "dmDb"; // 设置目标名称// 添加目标到配置中config.AddTarget(target.Name, target);// 创建日志规则var rule = new LoggingRule("*", LogLevel.Info, target); // 从 Info 级别开始记录config.LoggingRules.Add(rule);// 应用配置LogManager.Configuration = config;}else{Console.WriteLine("无法找到指定的目标类型.");}// 测试日志//var logger = LogManager.GetCurrentClassLogger();//logger.Debug("拐子大王来咯!");
先记录一下,后面有项目用到,直接拿着用吧。
相关文章:
Nlog适配达梦数据库进行日志插入
前言 原来使用的是SQLServer数据库,使用Nlog很流畅,没有什么问题。现在有个新项目需要使用麒麟操作系统和达梦数据库,业务流程开发完成之后发现Nlog配置文件中把数据库连接内容修改之后不能执行插入操作。 原Nlog.config配置 <?xml ve…...

k8s监控方案实践(三):部署与配置Grafana可视化平台
k8s监控方案实践(三):部署与配置Grafana可视化平台 文章目录 k8s监控方案实践(三):部署与配置Grafana可视化平台一、Grafana简介1. 什么是Grafana?2. Grafana与Prometheus的关系3. Grafana应用场…...

嵌入式系统架构验证工具:AADL Inspector v1.10 全新升级
软件架构建模与早期验证是嵌入式应用的关键环节。架构分析与设计语言(AADL)是专为应用软件及执行平台架构模型设计的语言,兼具文本与图形化的双重特性。AADL Inspector是一款轻量级的独立工具: 核心处理能力包括 √ 支持处理AA…...

STM32-模电
目录 一、MOS管 二、二极管 三、IGBT 四、运算放大器 五、推挽、开漏、上拉电阻 一、MOS管 1. MOS简介 这里以nmos管为例,注意箭头方向。G门极/栅极,D漏极,S源极。 当给G通高电平时,灯泡点亮,给G通低电平时&a…...

华为云Flexus+DeepSeek征文|从开通到应用:华为云DeepSeek-V3/R1商用服务深度体验
前言 本文章主要讲述在华为云ModelArts Studio上 开通DeepSeek-V3/R1商用服务的流程,以及开通过程中的经验分享和使用感受帮我更多开发者,在华为云平台快速完成 DeepSeek-V3/R1商用服务的开通以及使用入门注意:避免测试过程中出现部署失败等问…...

鸿蒙NEXT开发动画案例5
1.创建空白项目 2.Page文件夹下面新建Spin.ets文件,代码如下: /*** TODO SpinKit动画组件 - Pulse 脉冲动画* author: CSDN—鸿蒙布道师* since: 2024/05/09*/ ComponentV2 export struct SpinFive {// 参数定义Require Param spinSize: number 48;Re…...
面试篇:Spring MVC
基础概念 什么是Spring MVC? Spring MVC 是 Spring Framework 提供的一个基于 Servlet 的 Web 框架,属于 MVC(Model-View-Controller)架构的一种实现。它通过 DispatcherServlet 作为前端控制器,对请求进行分发和调度…...

ctfshow——web入门351~356
SSRF没有出网的部分 web入门351 $ch curl_init($url); 作用:初始化一个 cURL 会话,并设置目标 URL。解释: curl_init($url) 创建一个新的 cURL 资源,并将其与 $url 关联。这里的 $url 是用户提供的,因此目标地址完全…...
C++中六个特殊成员函数的关系
C中六个特殊成员函数的关系 C11之后的版本每个类有六个特殊的成员函数,之所以特殊是因为它们可以在各种情况下由编译器自动提供; 默认构造函数、复制构造函数、复制赋值运算符、析构函数、移动构造函数、移动赋值运算符 关系规则: 1、如果…...

【PostgreSQL数据分析实战:从数据清洗到可视化全流程】金融风控分析案例-10.1 风险数据清洗与特征工程
👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 PostgreSQL金融风控分析案例:风险数据清洗与特征工程实战一、案例背景:金融风控数据处理需求二、风险数据清洗实战(一)缺失值…...

美女热舞混剪视频批量剪辑生产技术实践:智能处理与原创性提升方案解析
一、引言:短视频工业化生产的技术转型 在美女类短视频内容运营中,通过标准化技术流程实现「高质量、规模化」产出成为核心需求。本文结合实战经验,解析如何通过智能素材重组、AI 语音合成、动态元素叠加等技术手段,构建自动化生产…...
破局智算瓶颈:400G光模块如何重构AI时代的网络神经脉络
一、技术演进与市场需求双重驱动 在数字化转型浪潮下,全球互联网流量正以每年30%的复合增长率持续攀升。根据Dell’Oro Group最新报告,2023年400G光模块市场规模已突破15亿美元,预计2026年将占据数据中心光模块市场60%以上份额。这种爆发式增…...
python标准库--collections - 高性能数据结构在算法比赛的应用
目录 一、deque双端队列 1.头部删除元素popleft() 2.BFS(广度优先搜索)优化 3.滑动窗口(双指针) 4.实现栈或队列 5. 双向遍历与操作 一、deque双端队列 特点:支持两端 O (1) 时间复杂度的…...

神经网络基础-从零开始搭建一个神经网络
一、什么是神经网络 人工神经网络(Articial Neural Network,简写为ANN)也称为神经网络(NN),是一种模仿生物神经网络和功能的计算模型,人脑可以看做是一个生物神经网络,由众多的神经元连接而成,各个神经元传递复杂的电信号,树突接收到输入信号,然后对信号进行处理,通…...
【Go】优化文件下载处理:从多级复制到零拷贝流式处理
在开发音频处理服务过程中,我们面临一个常见需求:从网络下载音频文件并保存到本地。这个看似简单的操作,实际上有很多优化空间。本文将分享一个逐步优化的过程,展示如何从一个基础实现逐步改进到高效的流式下载方案。 初始实现&a…...
Java 显式锁与 Condition 的使用详解
Java 显式锁与 Condition 的使用详解 在多线程编程中,线程间的协作与同步是核心问题。Java 提供了多种机制来实现线程同步,除了传统的 synchronized 关键字外,ReentrantLock 和 Condition 是更灵活且功能强大的替代方案。本文将详细介绍显式…...
android ViewModel liveData无法监听之多线程下activityViewModels不安全
我们一般的,会遇到liveData无法监听到结果,可能存在主要2种可能: liveData没有正确注册;liveData连续多次设置值,中间的值,会被丢弃,但最后一次是能监听到的。 但是我们容易忽略一种case&…...

#Redis黑马点评#(五)Redisson原理详解
目录 一 基于Redis的分布式锁优化 二 Redisson 1 实现步骤 2 Redisson可重入锁机制 3 Redisson可重试机制 4 Redisson超时释放机制 5 RedissonMultiLock解决主从一致性 三 trylock与lock两者有何区别 四 Redis优化秒杀 一 基于Redis的分布式锁优化 二 Redisson Redis…...

23.(vue3.x+vite)引入组件并动态切换(component)
让多个组件使用同一个挂载点,并动态切换,这就是动态组件 效果截图 A组件代码: <template><div><div>{{message }}</</...

VBA会被Python代替吗
VBA不会完全被Python取代、但Python在自动化、数据分析与跨平台开发等方面的优势使其越来越受欢迎、两者将长期并存且各具优势。 Python以其易于学习的语法、强大的开源生态系统和跨平台支持,逐渐成为自动化和数据分析领域的主流工具。然而,VBA依旧在Exc…...
2025 年福建省职业院校技能大赛网络建设与运维赛项Linux赛题解析
准备环境:系统安装及网络配置 [!TIP] 接下来将完全按照国赛评分标准进行,过程中需要掌握基础的Linux命令以及理解Linux系统,建议大家在做题前将Linux基础命令熟练运用 网络建设与运维赛项详细教程请联系主页一、X86架构计算机操作系统安装…...

SEMI E40-0200 STANDARD FOR PROCESSING MANAGEMENT(加工管理标准)-(三)完结
10 消息服务详情 10.1 本章定义实现加工管理概念所需的消息服务。这些消息已在第8.1节中初步介绍。 协议无关性:这些服务独立于所使用的消息协议,可映射至SECS-II(SEMI E5)或其他类似协议。 10.1.1 消息服务定义内容包括&#…...

MySQL数据库创建、删除、修改
一:建库建表 我们以学校体系进行建表。将数据库命名为school。 以下代码中的大写均可小写不影响。如CREATE DATABASE与create database相同 四个关键的实体分别是学院、老师、学生和课程,其中,学生跟学院是从属关系,这个关系从…...
招行数字金融挑战赛数据赛道赛题一
赛题描述:根据提供的用户行为数据,选手需要分析用户行为特征与广告内容的匹配关系,准确预测用户对测试集广告的点击情况,通过AUC计算得分。 得分0.6120,排名60。 尝试了很多模型都没有能够提升效果,好奇大…...

【氮化镓】GaN在不同电子能量损失的SHI辐射下的损伤
该文的主要发现和结论如下: GaN的再结晶特性 :GaN在离子撞击区域具有较高的再结晶倾向,这导致其形成永久损伤的阈值较高。在所有研究的电子能量损失 regime 下,GaN都表现出这种倾向,但在电子能量损失增加时,其效率会降低,尤其是在材料发生解离并形成N₂气泡时。 能量损失…...
容器化-Docker-私有仓库Harbor
一、Harbor 的含义与作用 Harbor 是一个开源的企业级 Docker 镜像仓库,它为用户提供了安全、高效的 Docker 镜像管理方案。其核心功能是集中管理 Docker 中所有的镜像,涵盖了镜像的存储、分发、版本控制等全生命周期管理。通过使用 Harbor,企业和团队能够显著提升 Docker…...
【Leetcode 每日一题】1550. 存在连续三个奇数的数组
问题背景 给你一个整数数组 a r r arr arr,请你判断数组中是否存在连续三个元素都是奇数的情况:如果存在,请返回 t r u e true true;否则,返回 f a l s e false false。 数据约束 1 ≤ a r r . l e n g t h ≤ 10…...
C#中SetProperty方法使用
SetProperty 是 MVVM(Model-View-ViewModel) 模式中用于实现 属性变更通知(INotifyPropertyChanged) 的核心方法,主要用于在属性值变化时自动更新 UI 绑定。 1. SetProperty 的基本作用 更新字段值:修改属性…...

防火墙来回路径不一致导致的业务异常
案例拓扑: 拓扑描述: 服务器有2块网卡,内网网卡2.2.2.1/24 网关2.2.254 提供内网用户访问; 外网网卡1.1.1.1/24,外网网关1.1.1.254 80端口映射到公网 这个时候服务器有2条默认路由,分布是0.0.0.0 0.0.0.0 1…...

WTK6900C-48L:离线语音芯片重构玩具DNA,从“按键操控”到“声控陪伴”的交互跃迁
一:开发背景 随着消费升级和AI技术进步,传统玩具的机械式互动已难以满足市场需求。语音控制芯片的引入使玩具实现了从被动玩耍到智能交互的跨越式发展。通过集成高性价比的语音识别芯片,现代智能玩具不仅能精准响应儿童指令,还能实…...