在 ABP VNext 中集成 Serilog:打造可观测、结构化日志系统

🚀 在 ABP VNext 中集成 Serilog:打造可观测、结构化日志系统


📚 目录

  • 🚀 在 ABP VNext 中集成 Serilog:打造可观测、结构化日志系统
    • 1. 为什么要使用结构化日志? 🤔
    • 2. 核心集成步骤 🛠
      • 2.1 流程图示例
    • 3. NuGet 包安装 📦
    • 4. appsettings.json 配置 📝
    • 5. Program.cs 全局日志初始化 💻
      • 5.1 代码流程图
    • 6. ABP 模块注册 🏗
    • 7. 上下文信息添加 🧩
      • 7.1 UseAbpSerilogEnrichers() 自动插入
      • 7.2 LogContext.PushProperty 自定义属性
    • 8. 对接平台:Seq & ELK & Grafana Loki 🌐
      • 8.1 部署 Seq(推荐开发阶段)
      • 8.2 部署 ELK(推荐生产环境)
        • 8.2.1 在 Kibana 中创建 Index Pattern 🔍
      • 8.3 对接 Grafana Loki(可选)🔗
    • 9. 总结 📋
    • 📎 推荐阅读 📚


1. 为什么要使用结构化日志? 🤔

相比于简单的文本日志,结构化日志有以下优势:

  • ❌ 传统文本日志无法根据 TraceId、UserId 等字段方便地检索
  • ❌ 无法像 SQL 那样对日志字段进行过滤与聚合
  • ❌ 不易在可视化平台(如 Kibana、Seq、Grafana Loki)上进行联动分析

而 Serilog 以原生的 JSON 日志形式输出,能够轻松处理上下文、分析调用链,方便与 ELK / Seq / Loki 等平台集成,做到精准定位故障点。


2. 核心集成步骤 🛠

步骤内容
1⃣️安装 Volo.Abp.AspNetCore.Serilog
2⃣️配置 Serilog Sink(Console、File、Seq、Elasticsearch、Loki)
3⃣️Program.cs 中初始化 Serilog
4⃣️在 ABP 模块中启用 UseAbpSerilogEnrichers() 插入上下文

2.1 流程图示例

启动项目
读取 appsettings.json 中 Serilog 配置
Program.cs 中 UseSerilog 初始化 Logger
创建 ABP 应用并调用 UseAbpSerilogEnrichers
HTTP 请求进入 → Enrichers 插入上下文
业务代码调用 ILogger 输出日志
Serilog 将日志写入 Console/File/Seq/ES/Loki
  • 通过 “Enrichers” 阶段,可以自动将 TraceId、UserId、MachineName 等信息注入到每条日志。

3. NuGet 包安装 📦

在项目根目录下执行以下命令,添加所需依赖包。为了避免版本不一致,建议指定版本号:

dotnet add package Volo.Abp.AspNetCore.Serilog 
dotnet add package Serilog.Sinks.Console          
dotnet add package Serilog.Sinks.File              
dotnet add package Serilog.Sinks.Seq               
dotnet add package Serilog.Sinks.Elasticsearch     # 如想支持 Grafana Loki:
dotnet add package Serilog.Sinks.Grafana.Loki      

4. appsettings.json 配置 📝

appsettings.json 文件中,添加或修改 Serilog 节点,如下所示:

{"Serilog": {"Using": ["Serilog.Sinks.Console","Serilog.Sinks.File","Serilog.Sinks.Seq","Serilog.Sinks.Elasticsearch","Serilog.Sinks.Grafana.Loki"],"MinimumLevel": {"Default": "Information","Override": {"Microsoft": "Warning","Microsoft.EntityFrameworkCore": "Error","Volo.Abp": "Information"}},"WriteTo": [{"Name": "Console"},{"Name": "File","Args": {"path":                 "Logs/log-.log","rollingInterval":      "Day","retainedFileCountLimit": 14,"fileSizeLimitBytes":   104857600,"buffered":             true,"flushToDiskInterval":  "00:00:05"}},{"Name": "Seq","Args": {"serverUrl": "http://localhost:5341"}},{"Name": "Elasticsearch","Args": {"nodeUris":                  "http://localhost:9200","indexFormat":               "myapp-logs-{0:yyyy.MM.dd}","autoRegisterTemplate":      true,"autoRegisterTemplateVersion": "ESv7","numberOfReplicas":          1,"numberOfShards":            5,"batchPostingLimit":         50,"period":                    "00:00:05","failureCallback":           "e => Console.WriteLine(\"Unable to submit event to Elasticsearch: \" + e.Message)"}},{"Name": "GrafanaLoki","Args": {"uri":                 "http://localhost:3100/loki/api/v1/push","batchPostingLimit":   50,"period":              "00:00:05","labels":              "{\"Application\":\"MyAbpApp\",\"Environment\":\"${env:ASPNETCORE_ENVIRONMENT}\"}"}}],"Enrich": ["FromLogContext","WithMachineName","WithThreadId","WithEnvironmentName"]}
}
  • Using:要加载的 Sink 包列表,包括 Console、File、Seq、Elasticsearch、Grafana Loki。
  • MinimumLevel:全局最低日志级别及对各命名空间的 Override。
  • WriteTo:各个输出通道的配置:
    • 📟 Console:控制台直接输出,适合开发与容器模式下采集标准输出。
    • 📂 File:写入本地文件,rollingInterval: Day 按天滚动;retainedFileCountLimit: 14 最多保留 14 天日志;fileSizeLimitBytes: 100MB,超出则滚动。
    • 📊 Seq:访问地址为 http://localhost:5341 的本地 Seq 服务。
    • 🔍 Elasticsearch:连接到 http://localhost:9200,索引名称按天命名;批量发送 50 条 / 5 秒;失败回调打印到控制台。
    • 📈 GrafanaLoki:连接本地 Loki(端口 3100)并打上标签,一旦在 Grafana 中按标签筛选,方便定位。
  • Enrich:注入常见上下文字段(如 TraceId、MachineName、ThreadId、Environment)。

Tip:如需在开发/生产环境区分配置,可分别在 appsettings.Development.jsonappsettings.Production.json 中覆盖 MinimumLevelWriteTo 节点。例如:

  • Development:将 MinimumLevel.Default 设置为 Debug,仅启用 Console Sink;
  • Production:将 MinimumLevel.Default 设置为 Information,启用 File、Seq、Elasticsearch、Loki Sink;并关闭 Console 输出以减少 I/O 压力。

5. Program.cs 全局日志初始化 💻

Program.cs 文件里,使用 Serilog 提供的“Bootstrap Logger”+“配置读取”模版,示例如下:

using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Volo.Abp.Serilog;namespace MyAbpApp
{public class Program{public static async Task Main(string[] args){// 1. 创建 Bootstrap Logger(只输出到 Console,用于捕获最早期的日志)Log.Logger = new LoggerConfiguration().MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Warning).WriteTo.Console().CreateBootstrapLogger();try{// 2. 构建 Host 并读取 appsettings.json 中的 Serilog 配置var builder = WebApplication.CreateBuilder(args);builder.Host.UseSerilog((ctx, services, config) =>{config.ReadFrom.Configuration(ctx.Configuration)    // 读取 appsettings.json 的 Serilog 设置.ReadFrom.Services(services)                  // 读取 DI 容器中注册的 ILogEventEnricher.Enrich.FromLogContext()                      // 从 LogContext 拉取附加属性.Enrich.WithProperty("Application", "MyAbpApp").Enrich.WithProperty("Environment", ctx.HostingEnvironment.EnvironmentName);});// 3. 添加 ABP 应用及所需模块builder.Services.AddApplication<MyAbpAppModule>();// 4. 构建应用var app = builder.Build();// 5. 注入 Serilog Enrichers(TraceId、UserId、TenantId 等)app.UseAbpSerilogEnrichers();// 6. 初始化 ABP 模块(包括 Routing、Authentication、Authorization 等)await app.InitializeApplicationAsync();// 7. 启动 HTTP 服务并阻塞await app.RunAsync();}catch (Exception ex){// 8. 捕获主机启动时的异常并记录 Fatal 日志Log.Fatal(ex, "Application start-up failed");Environment.ExitCode = 1;}finally{// 9. 应用退出时刷新并关闭日志Log.CloseAndFlush();}}}
}

5.1 代码流程图

Main 方法开始
创建 Bootstrap Logger
构建 WebHostBuilder
UseSerilog 读取配置并初始化 Logger
Services.AddApplication
Build 应用
UseAbpSerilogEnrichers 注入上下文
InitializeApplicationAsync 初始化 ABP 模块
RunAsync 启动 Kestrel 并监听请求
请求到达 → Enrichers 插入 TraceId 等
业务代码调用 ILogger 输出日志 → Serilog 写入 Sink
  • 该图展示了 Program.cs 中从 Main 开始,到最终应用启动并接收请求,日志如何一步步初始化并插入上下文的执行路径。

6. ABP 模块注册 🏗

MyAbpAppModule.cs 中声明所需的依赖模块,例如:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.BackgroundWorkers;
using Volo.Abp.DistributedEventBus;
using Volo.Abp.Modularity;
using Volo.Abp.TenantManagement;namespace MyAbpApp
{[DependsOn(typeof(AbpAspNetCoreSerilogModule),    // Serilog 集成模块typeof(AbpAspNetCoreMvcModule),        // MVC/Web API 基础模块typeof(AbpBackgroundWorkersModule),    // 后台任务模块(示例)typeof(AbpDistributedEventBusModule),  // 分布式事件总线模块(示例)typeof(AbpTenantManagementModule)      // 多租户管理模块(如需多租户场景))]public class MyAbpAppModule : AbpModule{public override void OnApplicationInitialization(ApplicationInitializationContext context){var logger = context.ServiceProvider.GetRequiredService<ILogger<MyAbpAppModule>>();logger.LogInformation("🔥 ABP 模块已启动!");}public override void OnApplicationShutdown(ApplicationShutdownContext context){var logger = context.ServiceProvider.GetRequiredService<ILogger<MyAbpAppModule>>();logger.LogInformation("💤 ABP 模块已关闭!");}}
}
  • 说明
    1. AbpAspNetCoreSerilogModule 会将 ABP 框架内部的日志重定向到 Serilog。
    2. 如果您的业务需要后台任务或分布式事件,请在 DependsOn 一并引入对应模块。
    3. 如果项目启用多租户,一定要引入 AbpTenantManagementModule 等租户相关模块。
    4. OnApplicationInitialization 中写一条“ABP 模块已启动”日志方便确认模块加载成功;在 OnApplicationShutdown 中写一条“ABP 模块已关闭”日志方便确认优雅退出。

7. 上下文信息添加 🧩

7.1 UseAbpSerilogEnrichers() 自动插入

Program.cs 中调用 app.UseAbpSerilogEnrichers(); 后,Serilog 会自动注入以下常见上下文字段到每条日志中:

  • 🔗 TraceId:分布式链路追踪 ID(需配合 OpenTelemetry/Jaeger 等链路追踪服务)
  • 👤 UserId、UserName:当前登录用户信息(需在请求上下文中有认证信息)
  • 🏷️ TenantId:当前多租户系统的租户 ID(如启用了多租户模块)
  • 🖥️ MachineName:主机名称(适用于集群调试)
  • 🧵 ThreadId:线程 ID(方便定位多线程日志)
  • 🌐 Environment:部署环境(如 Development、Production)

注意UseAbpSerilogEnrichers() 必须放在 UseRouting() 之后、UseAuthentication() 之前;如果您使用 ABP 脚手架模板,则无需手动调用中间件顺序,InitializeApplicationAsync() 已自动处理。

7.2 LogContext.PushProperty 自定义属性

在业务代码里,如果需要在单次请求或某个操作中,对特定实体(如 Order)添加自定义属性,可以使用 LogContext.PushProperty(...),示例如下:

using Serilog;
using Serilog.Context;
using Microsoft.Extensions.Logging;public class OrderService
{private readonly ILogger<OrderService> _logger;public OrderService(ILogger<OrderService> logger){_logger = logger;}public void ProcessOrder(Order order){// 在这个 using 块内,所有日志都会带上 OrderId 属性using (LogContext.PushProperty("OrderId", order.Id)){_logger.LogInformation("✅ Processing order {@Order}", order);// … 其它业务逻辑_logger.LogWarning("⚠️ Order {@Order} took too long to process", order);}}
}
  • 说明
    1. LogContext.PushProperty("OrderId", order.Id) 会在当前上下文中将 OrderId 写入所有后续日志。
    2. 使用 {@Order} 这种序列化写法,会把 Order 对象的所有字段写到 JSON 中,方便在 ES/Kibana/Loki 中查看结构化数据。
    3. 在控制台或日志平台中,该条日志会像:
      {"Timestamp": "2025-05-31T20:00:00.0000000Z","Level": "Information","MessageTemplate": "✅ Processing order {@Order}","Properties": {"OrderId": 12345,"Order": { "Id": 12345, "Amount": 99.99, "CustomerId": 67890 },"TraceId": "abcdef1234567890","UserId": 42,"TenantId": 1,"MachineName": "server01","ThreadId": 12,"Environment": "Production"}
      }
      

8. 对接平台:Seq & ELK & Grafana Loki 🌐

8.1 部署 Seq(推荐开发阶段)

docker run -d \-p 5341:80 \-v seq_data:/data \datalust/seq
  • 说明
    1. -p 5341:80 将容器 80 端口映射到宿主机 5341 端口;访问地址为 http://localhost:5341
    2. -v seq_data:/data 挂载一个 Docker 卷,用于持久化 Seq 数据;容器重启后数据依然保留。
    3. 启动后,可在 Seq Web 界面里创建 Dashboard,使用筛选条件(如 @l = "Error"@t >= "2025-05-01")进行日志定位。

8.2 部署 ELK(推荐生产环境)

创建一个 docker-compose.yml 文件,内容如下:

version: '3.7'volumes:es_data:kibana_data:services:elasticsearch:image: docker.elastic.co/elasticsearch/elasticsearch:7.17.0container_name: elasticsearchenvironment:- node.name=es-node-1- discovery.type=single-node- xpack.security.enabled=false- ES_JAVA_OPTS=-Xms1g -Xmx1gvolumes:- es_data:/usr/share/elasticsearch/dataports:- 9200:9200kibana:image: docker.elastic.co/kibana/kibana:7.17.0container_name: kibanaenvironment:- ELASTICSEARCH_HOSTS=http://elasticsearch:9200volumes:- kibana_data:/usr/share/kibana/dataports:- 5601:5601depends_on:- elasticsearch

运行:

docker-compose up -d
  • 说明
    1. Elasticsearch
      • 挂载 es_data 卷用以持久化数据;
      • 设置 JVM 堆大小为 1G(ES_JAVA_OPTS=-Xms1g -Xmx1g),生产环境可根据节点内存调整;
      • 关闭 X-Pack 安全认证方便本地测试;
    2. Kibana
      • 指定 ELASTICSEARCH_HOSTS 以连接 Elasticsearch;
      • 挂载 kibana_data 用于持久化 Kibana 配置;
      • 启动后访问 http://localhost:5601 即可登录;
8.2.1 在 Kibana 中创建 Index Pattern 🔍
  1. 打开 Kibana → 左侧菜单 “Management” → “Index Patterns” → “Create index pattern”。
  2. 在 “Index pattern name” 中输入 myapp-logs-*,点击 “Next step”。
  3. 选择时间字段(如 @timestamp)后点击 “Create index pattern”。
  4. 在 “Discover” 页面就能看到所有符合 myapp-logs-2025.05.XX 格式的索引,日志字段会以 JSON 形式展示,可以按字段进行过滤、排序、聚合。

提示:为了更直观地展示 Kibana 中的日志分组和聚合效果,可以创建一个简单的 Dashboard,比如“日志级别分布图”、“每小时错误请求数统计”等。这样在生产环境排查问题时,更加快捷。

8.3 对接 Grafana Loki(可选)🔗

如果您使用 Grafana Loki 作为日志收集平台,可参考以下步骤:

  1. 部署 Loki

    • 推荐使用 Loki 官方提供的 docker-compose.yml 或者 Helm Chart。
    • 简单示例(仅做测试用):
      version: '3.7'
      services:loki:image: grafana/loki:2.7.1container_name: lokicommand: -config.file=/etc/loki/local-config.yamlports:- 3100:3100promtail:image: grafana/promtail:2.7.1container_name: promtailvolumes:- /var/log:/var/log- ./promtail-config.yaml:/etc/promtail/config.yamlcommand: -config.file=/etc/promtail/config.yaml
      
    1. promtail-config.yaml 中,配置读取应用输出到标准输出(Console Sink)的日志,并推送到 Loki。
    2. 在 Grafana 中添加 Loki 数据源,创建 Dashboard 时选择 Loki 数据源即可查询 MyAbpApp 相关日志。
  2. GrafanaLoki Sink 配置示例
    已在第四节的 appsettings.json 中给出完整配置。再次回顾重点字段:

    {"Name": "GrafanaLoki","Args": {"uri": "http://localhost:3100/loki/api/v1/push","batchPostingLimit": 50,"period": "00:00:05","labels": "{\"Application\":\"MyAbpApp\",\"Environment\":\"Production\"}"}
    }
    
    • uri:Loki 的 Push API 地址;
    • batchPostingLimitperiod:控制批量推送频率;
    • labels:为日志打上标签,便于在 Grafana 中按标签筛选。

注意:在容器化环境下,将 uri 指向 Loki Service(如 http://loki:3100/loki/api/v1/push),不要使用 localhost


9. 总结 📋

  • 🚀 性能

    • 支持 bufferedflushToDiskInterval 控制文件写入 IO,平衡延迟与吞吐;
    • Elasticsearch Sink 中可配置 batchPostingLimitperiod,避免过于频繁的小批量请求。
  • 📈 规模

    • 支持日志按天滚动(rollingInterval: Day)和限制单文件大小(fileSizeLimitBytes),通过 retainedFileCountLimit 最多保留 14 天历史,防止磁盘耗尽。
  • 🎨 可视化

    • 结构化 JSON 日志让 Seq/Kibana/Loki 能以字段形式展示,可按字段、日期、级别精准搜索和聚合统计,大幅提升故障排查效率。
  • 🔧 可配置

    • 通过 appsettings.Development.jsonappsettings.Production.json 差异化配置,可在不同环境灵活切换最小日志级别与输出通道。
    • 支持自定义 Enrichers 和 Sink,能够将任意业务上下文(如 OrderId、ProductId、TraceId 等)注入到日志中。
  • 🐳 容器化注意

    • 如果服务跑在 Docker 或 Kubernetes,推荐保留 Console Sink 输出,通过容器平台日志采集(如 Fluentd、Filebeat、堆栈驱动)统一收集。
    • 若仍需写入日志文件,请确保挂载 Volume 以避免容器磁盘耗尽。
    • 根据目标平台(Seq、Elasticsearch、Loki)是否开启安全认证,需在对应 Sink 的 Args 中添加凭证信息(用户名、密码或 API Key)。

📎 推荐阅读 📚

  • ABP Serilog 模块文档
  • Serilog 官方文档
  • Seq 可视化平台
  • Grafana Loki 文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/83574.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

API异常信息如何实时发送到钉钉

#背景 对于一些重要的API&#xff0c;开发人员会非常关注API有没有报错&#xff0c;为了方便开发人员第一时间获取错误信息&#xff0c;我们可以使用插件来将API报错实时发送到钉钉群。 接下来我们就来实操如何实现 #准备工作 #创建钉钉群 如果已有钉钉群&#xff0c;可以跳…

Stone 3D新版本发布,添加玩家控制和生物模拟等组件,增强路径编辑功能,优化材质编辑

后续版本号改为构建日期加小版本&#xff0c;所以最新版本为20250603.01 功能更新如下&#xff1a; 1. 改写fps-controls组件&#xff0c;简化游戏应用的创建&#xff0c;你只需要一个场景glb&#xff0c;然后给Scene节点添加fps-controls组件&#xff0c;即可完成一个第一人…

【C++11】折叠引用和完美转发

目录 一. 前言二. 引用折叠引用折叠的规则 三. 完美转发完美转发适用场景完美转发底层实现思考1思考2 一. 前言 在函数传参时&#xff0c;如果想保持某个参数的属性不改变&#xff0c;需要完美转发&#xff0c;而完美转发的实现需要折叠引用的帮助 二. 引用折叠 在语法上&am…

Vue 树状结构控件

1、效果图如下所示&#xff1a; 2、网络请求的数据结构如下&#xff1a; 3、新建插件文件&#xff1a;menu-tree.vue&#xff0c;插件代码如下&#xff1a; <template><div class"root"><div class"parent" click"onParentClick(pare…

洛谷P12610 ——[CCC 2025 Junior] Donut Shop

题目背景 Score: 15. 题目描述 The owner of a donut shop spends the day baking and selling donuts. Given the events that happen over the course of the day, your job is to determine the number of donuts remaining when the shop closes. 输入格式 The first …

数据挖掘顶刊《IEEE Transactions on Knowledge and Data Engineering》2025年5月研究热点都有些什么?

本推文对2025年5月出版的数据挖掘领域国际顶级期刊《IEEE Transactions on Knowledge and Data Engineering》进行了分析&#xff0c;对收录的62篇论文的关键词与研究主题进行了汇总&#xff0c;并对其中的研究热点进行了深入分析&#xff0c;希望能为相关领域的研究人员提供有…

华为OD机试真题——最小的调整次数/特异性双端队列(2025B卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 B卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录+全流程解析/备考攻略/经验分享 华为OD机试真题《最小的调整次数/特异性双端…

2024年ESWA SCI1区TOP,自适应学习灰狼算法ALGWO+无线传感器网络覆盖优化,深度解析+性能实测

目录 1.端午快乐2.摘要3.灰狼算法GWO原理4.改进策略5.结果展示6.参考文献7.代码获取8.读者交流 1.端午快乐 今天端午节&#xff0c;祝各位朋友端午安康&#xff0c;阖家平安&#xff01; 2.摘要 无线传感器网络&#xff08;WSNs&#xff09;是一种被广泛应用的新兴技术&…

ADI硬件笔试面试题型解析下

本专栏预计更新60期左右。当前第17期-ADI硬件. ADI其硬件工程师岗位的招聘流程通常包括笔试和多轮技术面试,考察领域涵盖模拟电路设计、数字电路、半导体器件和信号处理等。 本文通过分析平台上的信息,汇总了ADI硬件工程师的典型笔试和面试题型,并提供详细解析和备考建议,…

SpringCloud 分布式锁Redisson锁的重入性与看门狗机制 高并发 可重入

可重入 Redisson 的锁支持 可重入性&#xff0c;这意味着同一个线程在获取锁后&#xff0c;如果再次尝试获取该锁&#xff0c;它可以成功地获得锁&#xff0c;而不会被阻塞。 每次一个线程成功获取锁后&#xff0c;它的持有次数会增加。当线程再次获取该锁时&#xff0c;Redi…

Java 中 Redis 过期策略深度解析(含拓展-redis内存淘汰策略列举)

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Java 中 Redis 过期策略深度解析一、Redis 过…

Flutter - 原生交互 - 相机Camera - 01

环境 Flutter 3.29 macOS Sequoia 15.4.1 Xcode 16.3 集成 Flutter提供了camera插件来拍照和录视频&#xff0c;它提供了一系列可用的相机&#xff0c;并使用特定的相机展示相机预览、拍照、录视频。 添加依赖 camera: 提供使用设备相机模块的工具path_provider: 寻找存储图…

基于 Amazon Q Developer CLI 和 Amazon Bedrock Knowledge Bases 实现智能问答系统

1. 引言 传统企业通常将常见问题&#xff08;FAQ&#xff09;发布在网站上&#xff0c;方便客户自助查找信息。然而&#xff0c;随着生成式 AI 技术的迅速发展与商业渗透&#xff0c;这些企业正积极探索构建智能问答系统的新途径。这类系统不仅能显著提升客户体验&#xff0c;…

Go 为何天生适合云原生?

当前我们正处在 AI 时代&#xff0c;但是在基础架构领域&#xff0c;仍然处在云原生时代。云原生仍然是当前时代的风口之一。作为一个 Go 开发者&#xff0c;职业进阶的下一站就是学习云原生技术。作为 Go 开发者学习云原生技术有得天独厚的优势&#xff0c;这是因为 Go 天生适…

Mac查看MySQL版本的命令

通过 Homebrew 查看&#xff08;如果是用 Homebrew 安装的&#xff09; brew info mysql 会显示你安装的版本、路径等信息。 你的终端输出显示&#xff1a;你并没有安装 MySQL&#xff0c;只是查询了 brew 中的 MySQL 安装信息。我们一起来看下重点&#xff1a; &#x1f9fe…

Kafka ACK机制详解:数据可靠性与性能的权衡之道

在分布式消息系统中&#xff0c;消息确认机制是保障数据可靠性的关键。Apache Kafka 通过 ACK&#xff08;Acknowledgment&#xff09;机制 实现了灵活的数据确认策略&#xff0c;允许用户在 数据可靠性 和 系统性能 之间进行权衡。本文将深入解析 Kafka ACK 机制的工作原理、配…

FastMCP:构建 MCP 服务器和客户端的高效 Python 框架

在人工智能领域&#xff0c;模型上下文协议&#xff08;Model Context Protocol&#xff0c;简称 MCP&#xff09;作为一种标准化的协议&#xff0c;为大型语言模型&#xff08;LLM&#xff09;提供了丰富的上下文和工具支持。而 FastMCP 作为构建 MCP 服务器和客户端的 Python…

动态库导出符号与extern “C“

1. windows下动态库导出符号 根据C/C语法规则&#xff0c;函数声明中的修饰符&#xff08;如__declspec(dllexport)&#xff09;可以放在返回类型之前或返回类型之后、函数名之前。这两种方式在功能上是等价的&#xff0c;编译器会以相同的方式处理。 __declspec(dllexport) …

Linux(9)——进程(控制篇——下)

目录 三、进程等待 1&#xff09;进程等待的必要性 2&#xff09;获取子进程的status 3&#xff09;进程的等待方法 wait方法 waitpid方法 多进程创建以及等待的代码模型 非阻塞的轮训检测 四、进程程序替换 1&#xff09;替换原理 2&#xff09;替换函数 3&…

Datatable和实体集合互转

1.使用已废弃的 JavaScriptSerializer&#xff0c;且反序列化为弱类型 ArrayList。可用但不推荐。 using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Linq; using System.Reflection; using System.Web; using Sy…