当前位置: 首页 > news >正文

C# 与.NET 日志变革:JSON 让程序“开口说清话”

一、引言:日志新时代的开启

在软件开发的漫长旅程中,日志一直是我们不可或缺的伙伴。它就像是应用程序的 “黑匣子”,默默地记录着程序运行过程中的点点滴滴,为我们在调试、排查问题以及性能优化时提供关键线索。在早期,文本日志是我们最常用的记录方式,它简单直接,就像我们随手写下的日记,记录着事件发生的时间、内容等基本信息。然而,随着软件系统规模的不断扩大,架构日益复杂,尤其是在微服务、大数据分析以及云原生应用盛行的今天,传统的文本日志渐渐显得力不从心。

想象一下,一个庞大的分布式系统,由成百上千个微服务组成,每个服务都在不断地产生日志。当出现问题时,面对堆积如山、格式各异的文本日志,开发人员和运维人员想要从中快速定位到关键信息,简直如同大海捞针。而且,文本日志的格式缺乏统一标准,不同团队、不同项目的日志风格千差万别,这就导致在进行日志分析时,难以使用自动化工具进行高效处理。

正是在这样的背景下,JSON 日志应运而生,它就像是为程序世界带来了一种全新的、更加时尚且高效的 “交流语言”。JSON(JavaScript Object Notation),这种轻量级的数据交换格式,以其简洁清晰的键值对结构,在数据传输和存储领域早已被广泛应用。而将其引入日志记录中,更是为日志管理带来了革命性的变化。

JSON 日志结构清晰,每个日志条目都以 JSON 对象的形式存在,不同的字段对应着不同的信息,比如时间戳、日志级别、事件描述、相关数据等,一目了然。这使得无论是开发人员手动查看,还是借助机器进行自动化解析和分析,都变得轻而易举。在大数据时代,我们可以轻松地将 JSON 日志与各种强大的日志分析工具,如 ELK Stack(Elasticsearch、Logstash、Kibana)、Splunk 等集成在一起,实现对海量日志数据的高效检索、统计分析以及可视化展示,从而快速洞察系统的运行状态,及时发现潜在的问题和风险 。

可以说,JSON 日志已经成为现代软件开发中不可或缺的一部分,它不仅提升了我们处理日志的效率和准确性,更让我们的程序能够以一种更加智能、高效的方式 “讲述” 自己的故事。接下来,就让我们一起深入 C# 与.NET 的世界,探索如何让 JSON 日志在我们的项目中大放异彩。

二、JSON 日志的独特魅力

(一)结构之美

JSON 日志的结构就如同精心规划的城市布局,每一个区域(字段)都有着明确的功能和定位。与传统的文本日志相比,它不再是冗长、无规律的文本堆砌 。例如,一段简单的文本日志可能是这样记录用户登录信息:“2024-12-10 10:30:00 INFO 用户 [张三] 登录成功,IP 地址为 192.168.1.100” 。这样的记录方式虽然人类可读,但对于机器来说,想要提取其中的关键信息,如时间、用户名、IP 地址等,就需要进行复杂的文本解析和正则表达式匹配,效率较低且容易出错。

而使用 JSON 日志,同样的信息可以表示为:

{
"timestamp": "2024-12-10T10:30:00Z",
"level": "INFO",
"user": "张三",
"event": "login",
"status": "success",
"ip": "192.168.1.100"
}

这种键值对的结构清晰明了,每个字段都有对应的含义,机器可以直接通过键名快速准确地获取所需信息,大大提高了数据处理的效率。在数据存储方面,JSON 日志的结构化特点也使得它更易于存储和管理。可以方便地将其存储在关系型数据库的特定字段中,或者直接存储在支持 JSON 格式的 NoSQL 数据库(如 MongoDB)中,充分利用数据库的索引和查询优化功能,提升数据检索的速度。

(二)机器友好性

在当今数字化时代,大量的日志数据需要依靠机器进行自动化处理和分析。JSON 日志因其简洁、规范的格式,成为了机器的 “宠儿”。几乎所有现代编程语言都提供了对 JSON 的解析支持,在 C# 中,我们可以使用System.Text.Json或Newtonsoft.Json等库轻松地解析和生成 JSON 数据。这意味着,无论我们的应用程序是运行在 Windows、Linux 还是 macOS 系统上,都能够快速地处理 JSON 日志。

以日志分析工具 ELK Stack 为例,Logstash 可以轻松地读取 JSON 格式的日志数据,并通过简单的配置对其进行过滤、转换和 enrichment 操作。然后,将处理后的数据发送到 Elasticsearch 进行存储和索引,Kibana 则可以从 Elasticsearch 中获取数据,并以直观的图表、报表等形式展示出来,帮助我们快速洞察系统的运行状态。相比之下,处理文本日志时,Logstash 需要使用复杂的 Grok 模式来解析日志内容,不仅配置难度大,而且容易出现解析错误。

(三)与现代技术栈的契合

在微服务架构中,一个大型应用程序被拆分成多个小型的、独立部署的服务,这些服务之间通过 HTTP、gRPC 等协议进行通信。每个微服务都会产生大量的日志,使用 JSON 日志可以方便地在不同的服务之间传递和共享日志信息,并且能够更好地与服务治理、监控等工具集成。例如,我们可以在日志中添加服务名称、请求 ID 等字段,通过这些字段可以轻松地追踪一个请求在整个微服务架构中的调用链路,快速定位问题所在。

对于大数据分析而言,JSON 日志的结构化和机器友好性使其成为理想的数据源。在 Hadoop、Spark 等大数据处理框架中,可以使用相应的库和工具对 JSON 日志进行高效的处理和分析。我们可以使用 Spark SQL 对存储在 HDFS 上的 JSON 日志数据进行 SQL 查询,统计不同类型事件的发生次数、分析用户行为模式等。

在云原生应用中,JSON 日志也能够很好地与云平台提供的日志管理服务集成。如 AWS CloudWatch、Google Cloud Logging 等,这些服务都原生支持 JSON 日志格式,能够方便地对日志进行收集、存储、查询和可视化展示,帮助我们更好地管理和运维云应用。

三、开启 JSON 日志之旅:准备工作

(一)引入关键 NuGet 包

在开始使用 JSON 日志之前,我们需要引入一些关键的 NuGet 包,它们就像是我们开启这场日志派对的 “入场券”。其中,Microsoft.Extensions.Logging和Microsoft.Extensions.Logging.Console是必不可少的。

Microsoft.Extensions.Logging是.NET Core 中日志处理的基础包,它提供了一套通用的日志记录接口和抽象,使得我们可以以一种统一的方式在不同的日志提供程序之间进行切换,而无需大量修改代码。就好比它为我们搭建了一个通用的舞台,不同的日志实现(如控制台日志、文件日志等)都可以在这个舞台上展示自己的功能 。

Microsoft.Extensions.Logging.Console则是专门用于将日志输出到控制台的提供程序包。在开发和调试过程中,控制台是我们最常用的日志输出目标之一,通过这个包,我们可以方便地将日志信息实时地显示在控制台窗口中,便于我们快速了解程序的运行状态。

引入这两个包的方式非常简单。如果你使用的是 Visual Studio,那么可以通过 NuGet 包管理器来进行操作。在解决方案资源管理器中,右键点击项目,选择 “管理 NuGet 程序包”,在弹出的窗口中搜索 “Microsoft.Extensions.Logging” 和 “Microsoft.Extensions.Logging.Console”,然后点击 “安装” 按钮即可。如果你更喜欢使用命令行,也可以在项目目录下打开命令提示符或终端,运行以下命令:

dotnet add package Microsoft.Extensions.Logging
dotnet add package Microsoft.Extensions.Logging.Console

这样,这两个包就会被成功添加到你的项目中,为后续的日志配置和使用做好准备。

(二)项目环境准备

在引入了必要的 NuGet 包之后,我们还需要确保项目环境的支持。首先,你需要创建一个新的.NET 项目,或者选择一个已有的项目来应用 JSON 日志。如果你是创建新项目,可以使用以下命令:

dotnet new console -n JsonLoggingDemo

这将创建一个名为 “JsonLoggingDemo” 的控制台应用项目。如果你使用的是 Visual Studio,也可以通过 “创建新项目” 向导来选择相应的项目模板进行创建。

确保你的项目所使用的.NET 环境版本支持这些 NuGet 包。一般来说,使用较新的.NET Core 或.NET 5 + 版本都能很好地支持。如果你的项目环境版本较低,可能需要进行升级,以确保能够充分利用 JSON 日志的功能和特性。你可以通过查看项目的.csproj文件来确认当前项目所使用的目标框架,例如:

<PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net6.0</TargetFramework>
</PropertyGroup>

如果TargetFramework的值不是你期望的版本,可以手动修改为合适的版本,然后重新恢复项目依赖(在命令行中运行dotnet restore)。

此外,还需要确保你的开发工具(如 Visual Studio、Visual Studio Code 等)已正确配置并能够识别和使用这些包。在 Visual Studio 中,你可以在 “工具”->“选项”->“NuGet 包管理器” 中进行相关设置;在 Visual Studio Code 中,需要安装相应的 C# 扩展,并确保项目的依赖项已正确加载。通过以上这些准备工作,我们的项目就已经具备了使用 JSON 日志的基本条件,接下来就可以开始进行具体的配置和代码编写了。

四、配置 JSON 日志输出

(一)appsettings.json 配置

在.NET 项目中,appsettings.json是一个常用的配置文件,我们可以在这里轻松地配置 JSON 日志输出。以下是一个配置示例:

{"Logging": {"LogLevel": {"Default": "Information","System": "Warning","Microsoft": "Warning"},"Console": {"FormatterName": "json"}}
}

让我们来详细解释一下这些参数的含义:

  • Logging:这是日志配置的根节点,所有与日志相关的配置都在这个节点下进行。

  • LogLevel:用于设置不同类别的日志级别。

    • Default:表示默认的日志级别,当没有为特定类别设置日志级别时,将使用这个默认级别。这里设置为Information,意味着默认情况下,Information级别及以上(如Warning、Error、Critical)的日志都会被记录。
    • System:针对System命名空间下的日志,设置为Warning,表示只有Warning级别及以上的日志才会被记录,而Debug和Information级别的日志将被忽略。
    • Microsoft:对于Microsoft相关命名空间的日志,同样设置为Warning,作用与System类似。通过这种方式,可以对不同来源的日志进行精细的控制,避免记录过多不必要的信息,同时确保关键的日志信息不会被遗漏。
  • Console:这个节点用于配置控制台日志输出相关的设置。

    • FormatterName:设置为json,表示我们希望控制台输出的日志采用 JSON 格式。这样,当我们在开发或调试过程中查看控制台日志时,看到的就是结构清晰的 JSON 日志,方便我们进行分析和处理。

通过在appsettings.json中进行这样的配置,我们就为项目初步设定了 JSON 日志输出的规则,使得应用程序在运行时能够按照我们的期望生成 JSON 格式的日志并输出到控制台 。

(二)代码中动态配置

虽然在appsettings.json中配置 JSON 日志输出简单方便,但在某些特殊场景下,我们可能需要在代码中动态地设置 JSON 日志。比如,根据不同的运行环境(开发环境、测试环境、生产环境),或者根据用户的特定需求,灵活地调整日志的配置。

在.NET 中,我们可以通过ILoggingBuilder来实现动态配置。以下是一个示例代码,展示了如何在Startup.cs文件中动态配置 JSON 日志输出:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;namespace JsonLoggingDemo
{public class Startup{public Startup(IConfiguration configuration){Configuration = configuration;}public IConfiguration Configuration { get; }public void ConfigureServices(IServiceCollection services){services.AddLogging(loggingBuilder =>{// 清除默认的日志提供程序loggingBuilder.ClearProviders();// 添加控制台日志提供程序,并设置为JSON格式loggingBuilder.AddConsole(options =>{options.FormatterName = "json";});// 可以根据条件进行更多的日志配置,例如:if (Environment.IsDevelopment()){// 在开发环境中,添加Debug日志提供程序loggingBuilder.AddDebug();}});// 其他服务配置...}public void Configure(IApplicationBuilder app, IWebHostEnvironment env){// 配置中间件...}}
}

在上述代码中,我们在ConfigureServices方法中,通过services.AddLogging来配置日志。首先,使用loggingBuilder.ClearProviders()清除了默认的日志提供程序,然后使用loggingBuilder.AddConsole添加了控制台日志提供程序,并通过options.FormatterName = "json"将其设置为 JSON 格式输出。

此外,我们还通过if (Environment.IsDevelopment())条件判断,在开发环境中添加了Debug日志提供程序,以便在开发过程中能够获取更详细的调试信息。这种动态配置的方式,使得我们的日志系统更加灵活和可定制,能够适应不同的应用场景和需求。

五、代码中的日志魔法

(一)ILogger 接口的使用

在 C# 与.NET 中,ILogger接口是记录日志的核心工具,它就像是我们在程序中安插的 “情报员”,时刻准备记录程序运行的关键信息。获取ILogger实例最常用的方式是通过构造函数注入 。这种方式不仅符合依赖注入的设计模式,还能让代码的依赖关系更加清晰,提高代码的可测试性和可维护性。

假设我们有一个名为UserService的服务类,它需要记录用户相关操作的日志。首先,我们需要在类中定义一个ILogger类型的私有字段,用于保存注入的日志记录器实例:

public class UserService
{private readonly ILogger<UserService> _logger;public UserService(ILogger<UserService> logger){_logger = logger;}// 其他业务方法...
}

在上述代码中,通过构造函数,我们将ILogger实例注入到UserService类中。这里的ILogger表示该日志记录器专门用于记录UserService类相关的日志信息,在日志中会自动包含UserService类的信息,方便我们在查看日志时快速定位到日志的来源。

当我们在UserService类的方法中需要记录日志时,就可以直接使用_logger字段来调用相应的日志记录方法。比如,在一个用户注册的方法中记录日志:

public void RegisterUser(string username)
{_logger.LogInformation($"开始注册用户:{username}");// 模拟用户注册的业务逻辑//..._logger.LogInformation($"用户 {username} 注册成功");
}

这样,在用户注册的过程中,关键的操作步骤都被记录到了日志中,为后续的调试和问题排查提供了详细的信息。

(二)记录不同级别的日志

在日志记录中,不同级别的日志就像是不同颜色的信号灯,分别代表着不同的紧急程度和重要性,帮助我们快速筛选和定位关键信息。在 C# 与.NET 中,常用的日志级别有以下几种:

  • 信息(Information):用于记录程序正常运行过程中的重要信息,比如业务流程的关键步骤、系统状态的变化等。这些信息有助于我们了解程序的整体运行情况,在上面的UserService.RegisterUser方法中,记录用户注册的开始和成功信息就使用了LogInformation方法,这是在日常运行中非常有用的信息记录,能够让我们清晰地跟踪业务流程的执行情况。

  • 警告(Warning):当程序出现一些潜在的问题,但这些问题暂时不会影响程序的正常运行时,使用警告级别日志。例如,当系统检测到某个资源的使用接近上限,或者某个操作出现了一些不常见但还未导致错误的情况时,可以记录警告日志。比如:

_logger.LogWarning("数据库连接池剩余连接数不足,仅剩5个,可能影响系统性能");

这样,运维人员或开发人员在查看日志时,就能及时发现潜在的问题,并采取相应的措施进行优化或预防。

  • 错误(Error):当程序发生错误,导致某个功能无法正常执行时,使用错误级别日志。记录错误日志时,通常会包含错误的详细信息,如错误消息、堆栈跟踪等,以便开发人员能够快速定位和解决问题。例如:
try
{// 可能会抛出异常的代码int result = 10 / 0;
}
catch (Exception ex)
{_logger.LogError(ex, "发生除零错误,计算失败");
}

在上述代码中,当发生除零错误时,LogError方法会记录异常对象ex以及错误描述信息,通过堆栈跟踪信息,开发人员可以准确地知道错误发生的位置和调用链路。

  • 致命(Critical):用于记录极其严重的错误,这些错误会导致整个程序无法继续运行,比如系统关键组件崩溃、数据库连接完全丢失等。一旦出现致命错误,需要立即采取紧急措施进行处理。例如:
try
{// 模拟一个导致系统崩溃的严重错误throw new Exception("系统核心组件出现致命错误,无法继续运行");
}
catch (Exception ex)
{_logger.LogCritical(ex, "系统发生致命错误,即将终止");
}

在这种情况下,LogCritical方法记录的日志能够帮助我们快速了解系统崩溃的原因,以便进行紧急修复和恢复工作。

(三)异常处理与日志记录

在程序运行过程中,异常是不可避免的。而正确地处理异常并记录相关日志,是保证程序健壮性和可维护性的关键。当捕获到异常时,记录详细的异常信息到日志中是非常重要的,它就像是留下了问题的 “线索”,帮助我们在后续能够快速地定位和解决问题。

以下是一个在方法中捕获异常并记录日志的示例:

public void ProcessData()
{try{// 模拟数据处理操作,可能会抛出异常string data = null;int length = data.Length;}catch (Exception ex){_logger.LogError(ex, "数据处理过程中出现异常");// 可以根据具体情况进行异常处理,比如进行重试、回滚操作等// 这里简单地重新抛出异常,让上层调用者决定如何处理throw;}
}

在上述代码中,当data为null时,调用data.Length会抛出NullReferenceException异常。在catch块中,我们使用_logger.LogError方法记录了异常信息,包括异常对象ex和错误描述 “数据处理过程中出现异常”。通过记录异常对象,日志中会包含详细的堆栈跟踪信息,这对于开发人员来说是非常宝贵的调试信息。它可以告诉我们异常发生的具体位置,以及在异常发生之前程序的调用链路,从而帮助我们快速定位问题的根源。

此外,在记录异常日志后,我们还可以根据具体的业务需求进行进一步的处理。比如,在某些情况下,我们可以尝试进行重试操作,以确保数据处理的成功;或者进行回滚操作,以保证数据的一致性。而无论采取何种处理方式,详细的日志记录都是我们做出正确决策的重要依据。

六、深度定制:打造专属 JSON 日志

(一)自定义 JsonLoggerProvider

虽然.NET 提供的默认 JSON 日志配置已经能够满足大多数场景的需求,但在一些复杂的业务场景下,我们可能需要更加个性化的日志记录方式。这时候,自定义JsonLoggerProvider就派上用场了。

自定义JsonLoggerProvider的主要作用是让我们能够完全掌控日志的生成和输出过程,根据自己的业务逻辑和需求,定制独特的日志记录策略。比如,我们可以在日志中添加一些自定义的元数据,或者根据不同的条件动态地调整日志的输出格式。

下面是一个简单的自定义JsonLoggerProvider的示例代码:

using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Threading;public class CustomJsonLoggerProvider : ILoggerProvider
{private readonly Func<string, LogLevel, bool> _filter;private readonly ConcurrentDictionary<string, CustomJsonLogger> _loggers = new ConcurrentDictionary<string, CustomJsonLogger>();public CustomJsonLoggerProvider(Func<string, LogLevel, bool> filter = null){_filter = filter;}public ILogger CreateLogger(string categoryName){return _loggers.GetOrAdd(categoryName, name => new CustomJsonLogger(name, _filter));}public void Dispose(){_loggers.Clear();}
}public class CustomJsonLogger : ILogger
{private readonly string _categoryName;private readonly Func<string, LogLevel, bool> _filter;public CustomJsonLogger(string categoryName, Func<string, LogLevel, bool> filter = null){_categoryName = categoryName;_filter = filter;}public IDisposable BeginScope<TState>(TState state){return null;}public bool IsEnabled(LogLevel logLevel){return _filter == null || _filter(_categoryName, logLevel);}public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter){if (!IsEnabled(logLevel)){return;}// 这里开始构建自定义的JSON日志内容var logEntry = new{Timestamp = DateTime.UtcNow,LogLevel = logLevel.ToString(),Category = _categoryName,EventId = eventId.Id,Message = formatter(state, exception),Exception = exception?.ToString()};// 这里可以根据需要将logEntry序列化为JSON字符串并输出到指定目标,比如文件、数据库等Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(logEntry));}
}

在上述代码中,我们首先定义了CustomJsonLoggerProvider类,它实现了ILoggerProvider接口。在CreateLogger方法中,我们根据categoryName创建并返回一个CustomJsonLogger实例。如果已经存在相同categoryName的CustomJsonLogger,则直接从_loggers字典中获取。

CustomJsonLogger类实现了ILogger接口,在Log方法中,我们构建了一个包含时间戳、日志级别、类别、事件 ID、消息和异常信息的匿名对象logEntry。然后,通过Newtonsoft.Json.JsonConvert.SerializeObject方法将其序列化为 JSON 字符串,并输出到控制台。这里的输出方式可以根据实际需求进行修改,比如写入文件、发送到远程日志服务器等。

在使用自定义的JsonLoggerProvider时,我们可以在Startup.cs文件中进行如下配置:

public void ConfigureServices(IServiceCollection services)
{services.AddLogging(loggingBuilder =>{loggingBuilder.ClearProviders();loggingBuilder.AddProvider(new CustomJsonLoggerProvider((category, logLevel) =>{// 这里可以根据category和logLevel进行过滤,只记录满足条件的日志return logLevel >= LogLevel.Information;}));});
}

通过上述配置,我们清除了默认的日志提供程序,然后添加了自定义的CustomJsonLoggerProvider,并设置了日志过滤条件,只记录Information级别及以上的日志。

(二)定制 JsonFormatter

除了自定义JsonLoggerProvider,我们还可以通过定制JsonFormatter来进一步调整 JSON 日志的输出样式,使其更加符合我们的业务需求。定制JsonFormatter可以让我们在日志中添加自定义字段、格式化时间、调整日志结构等。

下面是一个定制JsonFormatter的示例,展示如何添加自定义字段和格式化时间:

using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Logging.Console;
using System;
using System.Collections.Generic;
using System.Text.Json;public class CustomJsonFormatter : ConsoleFormatter
{public CustomJsonFormatter() : base("CustomJson"){}public override void Write<TState>(in LogEntry<TState> logEntry, IExternalScopeProvider scopeProvider, TextWriter textWriter){var logObject = new Dictionary<string, object>();// 添加时间戳字段,并格式化时间logObject.Add("Timestamp", logEntry.Timestamp.ToString("yyyy-MM-dd HH:mm:ss.fff"));// 添加日志级别字段logObject.Add("Level", logEntry.LogLevel.ToString());// 添加类别字段logObject.Add("Category", logEntry.Category);// 添加事件ID字段logObject.Add("EventId", logEntry.EventId.Id);// 添加自定义字段logObject.Add("CustomField", "This is a custom field value");// 添加消息字段var message = logEntry.Formatter(logEntry.State, logEntry.Exception);logObject.Add("Message", message);// 如果有异常,添加异常信息字段if (logEntry.Exception!= null){logObject.Add("Exception", logEntry.Exception.ToString());}// 使用System.Text.Json将日志对象序列化为JSON字符串并写入文本写入器var options = new JsonWriterOptions { Indented = true };using (var jsonWriter = new Utf8JsonWriter(textWriter.AsStream(), options)){JsonSerializer.Serialize(jsonWriter, logObject);}textWriter.WriteLine();}
}

在上述代码中,我们定义了CustomJsonFormatter类,它继承自ConsoleFormatter。在Write方法中,我们创建了一个Dictionary<string, object>类型的logObject,用于存储日志的各个字段。

首先,我们添加了Timestamp字段,并使用ToString(“yyyy-MM-dd HH:mm:ss.fff”)方法将时间格式化为指定的字符串形式。接着,依次添加了Level、Category、EventId、CustomField、Message和Exception等字段。其中,CustomField就是我们添加的自定义字段,可以根据实际需求设置其值。

最后,使用System.Text.Json将logObject序列化为 JSON 字符串,并通过Utf8JsonWriter将其写入到textWriter中。options.Indented = true表示生成的 JSON 字符串会进行缩进,使其更加易读。

在使用定制的JsonFormatter时,我们可以在Startup.cs文件中进行如下配置:

public void ConfigureServices(IServiceCollection services)
{services.AddLogging(loggingBuilder =>{loggingBuilder.AddConsole(options =>{options.FormatterName = "CustomJson";options.UseUtcTimestamp = true;options.FormatterOptions = new JsonConsoleFormatterOptions{JsonWriterOptions = new JsonWriterOptions { Indented = true }};});loggingBuilder.AddProvider(new ConsoleLoggerProvider((_, __) => true, true){FormatterName = "CustomJson"});loggingBuilder.Services.AddSingleton<ConsoleFormatter, CustomJsonFormatter>();});
}

通过上述配置,我们在AddConsole方法中设置了FormatterName为CustomJson,并配置了一些其他的选项,如使用 UTC 时间戳、设置 JSON 写入器的缩进选项等。然后,添加了一个ConsoleLoggerProvider,并指定其FormatterName也为CustomJson。最后,通过services.AddSingleton<ConsoleFormatter, CustomJsonFormatter>()将我们定制的CustomJsonFormatter注册到服务容器中,使其能够被正确使用。这样,在应用程序运行时,日志就会按照我们定制的JsonFormatter的样式进行输出。

七、实践案例:JSON 日志在项目中的应用

(一)案例背景介绍

我们的项目是一个大型的电商微服务平台,涵盖了用户管理、商品展示、订单处理、支付结算等多个核心业务模块,每天处理数以万计的用户请求和交易。随着业务的快速增长和用户量的不断攀升,系统的复杂性也日益增加,传统的文本日志在应对如此庞大和复杂的日志数据时,逐渐暴露出诸多问题。

在业务层面,我们需要精确地跟踪用户在平台上的每一个操作,包括用户的浏览行为、商品搜索记录、加入购物车的操作以及最终的下单和支付过程,以便进行精准的用户行为分析和个性化推荐。然而,文本日志难以快速、准确地提取这些关键信息,导致我们在分析用户行为和优化业务流程时面临很大的困难。

在系统运维方面,当出现故障或性能问题时,我们需要能够迅速定位问题所在,确定是哪个微服务出现了故障,以及故障发生的具体时间和原因。但由于文本日志格式不统一,各个微服务的日志风格各异,使得故障排查变得异常艰难,严重影响了系统的可用性和稳定性。

为了更好地满足业务发展和系统运维的需求,我们决定引入 JSON 日志,期望通过其结构化和机器友好的特性,提升日志管理的效率和质量,为业务决策和系统优化提供有力支持。

(二)实施过程与遇到的问题

  1. 实施步骤
    • 引入依赖:在项目的各个微服务中,我们首先引入了Microsoft.Extensions.Logging和Microsoft.Extensions.Logging.Console NuGet 包,为使用 JSON 日志奠定基础。通过包管理器或手动修改.csproj文件,确保这些依赖被正确添加到项目中。
    • 配置日志输出:在appsettings.json文件中,我们进行了详细的日志配置。设置了不同类别的日志级别,根据业务需求和系统运行情况,将核心业务模块的日志级别设置为Information,以记录关键业务操作;将一些辅助模块的日志级别设置为Warning,仅记录潜在的问题。同时,将控制台日志的FormatterName设置为json,使日志以 JSON 格式输出到控制台,方便开发和调试过程中的查看。
    • 代码中集成日志记录:在每个微服务的代码中,通过构造函数注入的方式获取ILogger实例。在关键业务逻辑处,如用户注册、商品下单、支付处理等方法中,使用ILogger记录不同级别的日志。在用户注册方法中,使用LogInformation记录用户注册的开始和成功信息;在支付处理方法中,使用LogError记录支付失败的异常信息,包括异常对象和详细的错误描述。
  1. 遇到的问题及解决方法
    • 性能优化问题:在引入 JSON 日志初期,我们发现系统的性能有所下降,尤其是在高并发场景下。经过分析,发现是由于频繁的 JSON 序列化和反序列化操作导致的。为了解决这个问题,我们对日志记录的频率进行了优化,减少不必要的日志记录。同时,对一些性能敏感的业务逻辑,采用异步的方式进行日志记录,避免日志操作阻塞主线程。
    • 格式兼容性问题:在将 JSON 日志与现有的日志分析工具 ELK Stack 集成时,遇到了格式兼容性问题。由于 ELK Stack 对 JSON 日志的格式有一定的要求,而我们最初生成的 JSON 日志格式与 ELK Stack 的期望格式存在一些差异,导致日志数据无法正常被 ELK Stack 解析和处理。通过仔细研究 ELK Stack 的文档和配置选项,我们对 JSON 日志的格式进行了调整,确保每个字段的名称和数据类型符合 ELK Stack 的要求。在日志中添加了@timestamp字段,并按照 ELK Stack 的时间格式要求进行了格式化,最终成功实现了 JSON 日志与 ELK Stack 的无缝集成。

(三)应用效果展示

  1. 日志分析效率大幅提升:使用 JSON 日志后,我们可以利用 ELK Stack 强大的搜索和分析功能,快速地对日志数据进行查询和统计。通过在 Kibana 中创建各种可视化报表,如用户行为分析报表、系统性能监控报表等,能够直观地了解系统的运行状态和用户的行为模式。在分析用户的购买行为时,可以通过简单的查询语句,快速筛选出特定时间段内购买了某类商品的用户列表,以及他们的购买频率和平均消费金额等信息,为精准营销和商品推荐提供了有力的数据支持。

  2. 问题定位速度显著加快:当系统出现问题时,通过 JSON 日志中清晰的结构化信息,我们能够迅速定位到问题所在。在订单处理模块出现错误时,日志中会详细记录错误发生的时间、相关的微服务名称、方法名以及异常信息,包括堆栈跟踪。开发人员可以根据这些信息,快速定位到错误的代码位置,大大缩短了故障排查的时间。在一次支付失败的问题排查中,通过查看 JSON 日志,我们在几分钟内就确定了是由于支付接口的参数传递错误导致的,迅速解决了问题,减少了对用户的影响。

八、总结与展望

(一)回顾 JSON 日志的优势与实践成果

通过前面的介绍和实践案例,我们深刻领略到了 JSON 日志在 C# 与.NET 开发中的显著优势。从结构上看,它以清晰的键值对形式组织日志信息,告别了传统文本日志的杂乱无章,无论是人工查阅还是机器解析都变得轻松高效。在与各种现代技术栈的融合方面,JSON 日志更是展现出了强大的适应性和兼容性,无论是微服务架构、大数据分析场景,还是云原生应用环境,它都能完美融入,为系统的监控、调试和优化提供有力支持。

在实际项目应用中,我们的电商微服务平台引入 JSON 日志后,成功解决了日志管理方面的诸多难题。通过与 ELK Stack 的集成,实现了对海量日志数据的高效分析和可视化展示,大大提升了问题定位的速度和准确性,为业务的稳定运行和持续发展提供了坚实保障。这充分证明了 JSON 日志在复杂业务场景下的实用性和价值。

(二)对未来日志发展的展望

随着技术的不断进步,未来的日志发展将呈现出更加多元化和智能化的趋势。JSON 日志作为当前日志管理的主流选择,也将在这一趋势下不断演进和发展。在人工智能和机器学习技术日益成熟的背景下,JSON 日志有望与这些技术深度融合。通过对大量历史日志数据的学习和分析,利用机器学习算法实现日志异常检测、故障预测等功能。通过建立日志数据的正常行为模型,当检测到日志数据偏离正常模式时,及时发出警报,提前预防系统故障的发生。利用自然语言处理技术,对 JSON 日志中的文本信息进行分析和理解,实现更加智能化的日志搜索和问题诊断。

随着边缘计算、物联网等新兴技术的快速发展,将产生海量的设备日志数据。JSON 日志因其轻量级和结构化的特点,将在这些领域发挥重要作用,帮助我们更好地管理和分析这些设备产生的日志,实现对设备状态的实时监控和智能管理。

此外,随着安全和隐私保护意识的不断提高,未来的 JSON 日志可能会更加注重数据的加密和隐私保护,确保日志数据在传输和存储过程中的安全性。在日志格式和标准方面,也可能会出现更加统一和规范的趋势,以便于不同系统和工具之间的日志交换和共享。

JSON 日志已经为我们的程序世界带来了一场 “时尚变革”,而未来,它将继续引领日志管理的发展潮流,为软件开发和运维带来更多的创新和价值。作为开发者,我们应紧跟技术发展的步伐,不断探索和应用 JSON 日志的新功能和新特性,让我们的程序能够以更加智能、高效的方式与我们 “沟通”,共同推动软件行业的进步和发展。

相关文章:

C# 与.NET 日志变革:JSON 让程序“开口说清话”

一、引言&#xff1a;日志新时代的开启 在软件开发的漫长旅程中&#xff0c;日志一直是我们不可或缺的伙伴。它就像是应用程序的 “黑匣子”&#xff0c;默默地记录着程序运行过程中的点点滴滴&#xff0c;为我们在调试、排查问题以及性能优化时提供关键线索。在早期&#xff…...

Ubuntu 系统,如何使用双Titan V跑AI

要在Ubuntu系统中使用双NVIDIA Titan V GPU来运行人工智能任务&#xff0c;你需要确保几个关键组件正确安装和配置。以下是基本步骤&#xff1a; 安装Ubuntu操作系统&#xff1a; 下载最新版本的Ubuntu服务器或桌面版ISO文件。使用工具如Rufus&#xff08;Windows&#xff09;或…...

CSDN的历史

CSDN(中国开发者网络,China Software Developer Network)是中国最具影响力的IT技术社区之一,其历史可追溯至1999年。以下是其发展历程和关键节点: --- **一、创立背景(1999年)** - **创始人**:蒋涛(国内知名技术人,曾参与金山软件早期开发)。 - **初衷**:为国内程…...

使用Pygame制作“贪吃蛇”游戏

贪吃蛇 是一款经典的休闲小游戏&#xff1a;玩家通过操控一条会不断变长的“蛇”在屏幕中移动&#xff0c;去吃随机出现的食物&#xff0c;同时要避免撞到墙壁或自己身体的其他部分。由于其逻辑相对简单&#xff0c;但可玩性和扩展性都不错&#xff0c;非常适合作为新手练习游戏…...

【详细教程】如何在Mac部署Deepseek R1?

DeepSeek是目前最火的国产大模型&#xff0c;官方App用户太多服务经常出现卡顿&#xff0c;部署一个本地DeepSeek R1可以方便使用。 1.系统最低要求 macOS 11 Big Sur 或更新 2.下载ollama https://ollama.com/ 3.安装DeepSeek R1 打开终端 运行命令 ollama run deepseek-…...

Java中的getInterfaces()方法:使用与原理详解

在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一个强大的工具&#xff0c;它允许程序在运行时动态地获取类的信息并操作类的属性和方法。getInterfaces()方法是Java反射API中的一个重要方法&#xff0c;用于获取类或接口直接实现的接口。本文将深入探讨getInt…...

PT站点自动签到

在站点下载一些视频电影资源&#xff0c;站点需要长期维护&#xff0c;每天自动签到。 两种方式&#xff1a; 一、保持浏览器登录状态&#xff0c;打开默认用户文件&#xff0c; 模拟点击签到&#xff08;点击按钮自行设置&#xff1a;根据href名称&#xff09; log日志 首次…...

计算机网络一点事(23)

传输层 端口作用&#xff1a;标识主机特定进程&#xff0c;TCP&#xff0c;UDP协议 端口号分类&#xff1a;服务器&#xff1a;0-1023&#xff0c;熟知 1024-49151 登记 客户端&#xff1a;49152-65535 功能&#xff1a;实现端到端&#xff0c;进程到进程的通信&#xff0c…...

vim操作简要记录

操作容易忘记&#xff0c;记录一下基本使用的 :wq保存退出 :w :q :q! :wq! i I a A 方向键 h左 j下 k上 l右 dd删除方行&#xff08;这其实是剪切行操作&#xff0c;不过一般用作删除&#xff0c;长按可删除&#xff0c;不过按.执行上一次操作删除更快&#xff09; .执行上…...

DeepSeek大模型技术深度解析:揭开Transformer架构的神秘面纱

摘要 DeepSeek大模型由北京深度求索人工智能基础技术研究有限公司开发&#xff0c;基于Transformer架构&#xff0c;具备卓越的自然语言理解和生成能力。该模型能够高效处理智能对话、文本生成和语义理解等复杂任务&#xff0c;标志着人工智能在自然语言处理领域的重大进展。 关…...

Carla-ModuleNotFoundError: No module named ‘agents.navigation‘

解决办法&#xff1a; You need to make sure that _agents _ is in your (PYTHON)PATH variable or your working dictionary. Setting your working dictionary to <CARLA_ROOT>/PythonAPI/carla would fix it as agents is a sub dictionary. Similarly adding the c…...

1.Template Method 模式

模式定义 定义一个操作中的算法的骨架&#xff08;稳定&#xff09;&#xff0c;而将一些步骤延迟&#xff08;变化)到子类中。Template Method 使得子类可以不改变&#xff08;复用&#xff09;一个算法的结构即可重定义&#xff08;override 重写&#xff09;该算法的某些特…...

腾讯云开发提供免费GPU服务

https://ide.cloud.tencent.com/dashboard/web 适用于推理场景&#xff0c;每个月10000分钟免费时长 166 小时 40 分钟 自带学术加速&#xff0c;速度还是不错的 白嫖 Tesla T4 16G 算力 显存&#xff1a;16GB 算力&#xff1a;8 TFlops SP CPU&#xff1a;8 核 内存&#…...

11.QT控件:输入类控件

1. Line Edit(单行输入框) QLineEdit表示单行输入框&#xff0c;用来输入一段文本&#xff0c;但是不能换行。 核心属性&#xff1a; 核心信号&#xff1a; 2. Text Edit(多行输入框) QTextEdit表示多行输入框&#xff0c;也是一个富文本 & markdown编辑器。并且能在内容超…...

想学习Python编程,应该如何去学习呢

学习Python编程是一个循序渐进的过程&#xff0c;以下是一个详细的学习路径和建议&#xff1a; 一、基础入门 安装Python环境&#xff1a; 从Python官方网站下载并安装适合你操作系统的Python版本。确保将Python添加到系统路径中&#xff0c;以便在命令行中方便地访问。 学习…...

Java知识速记:深拷贝与浅拷贝

Java知识速记&#xff1a;深拷贝与浅拷贝 什么是浅拷贝&#xff1f; 浅拷贝指的是创建一个新对象&#xff0c;但新对象的属性值是对原对象属性值的引用。当原对象的属性是基本类型时&#xff0c;浅拷贝能够直接复制其值&#xff1b;当属性是对象时&#xff0c;仅复制引用&…...

I2C基础知识

引言 这里祝大家新年快乐&#xff01;前面我们介绍了串口通讯协议&#xff0c;现在我们继续来介绍另一种常见的简单的串行通讯方式——I2C通讯协议。 一、什么是I2C I2C 通讯协议&#xff08;Inter-Integrated Circuit&#xff09;是由Phiilps公司在上个世纪80年代开发的&#…...

智慧园区平台系统在数字化转型中的作用与应用前景探究

内容概要 在当前快速变化的商业环境中&#xff0c;数字化转型已经成为企业发展的重要趋势&#xff0c;而智慧园区平台系统则是这一转型的核心工具之一。这种系统集成了多种现代技术&#xff0c;能够有效提升园区的管理效率、优化资产使用&#xff0c;并提升整体服务水平。智慧…...

19 压测和常用的接口优化方案

高并发的平台应用&#xff0c;项目上线前离不开一个重要步骤就是压测&#xff0c;压测对于编码中的资源是否问题的排查&#xff0c;性能的调优都是离不开的。测试还要做测试报告&#xff0c;出具了测试报告给到运维团队才能上线。 压测的测试报告主要有以下几个方面:1.响应时间…...

buuuctf_秘密文件

题目&#xff1a; 应该是分析流量包了&#xff0c;用wireshark打开 我追踪http流未果&#xff0c;分析下ftp流 追踪流看看 用户 “ctf” 使用密码 “ctf” 登录。 PORT命令用于为后续操作设置数据连接。 LIST命令用于列出 FTP 服务器上目录的内容&#xff0c;但在此日志中未…...

前端学习-事件委托(三十)

目录 前言 课前思考 for循环注册事件 语法 事件委托 1.事件委托的好处是什么? 2.事件委托是委托给了谁&#xff0c;父元素还是子元素 3.如何找到真正触发的元素 示例代码 总结 前言 才子佳人&#xff0c;自是白衣卿相 课前思考 1.如果同时给多个元素注册事件&…...

工具的应用——安装copilot

一、介绍Copilot copilot是一个AI辅助编程的助手&#xff0c;作为需要拥抱AI的程序员可以从此尝试进入&#xff0c;至于好与不好&#xff0c;应当是小马过河&#xff0c;各有各的心得。这里不做评述。重点在安装copilot的过程中遇到了一些问题&#xff0c;然后把它总结下&…...

OPENGLPG第九版学习

文章目录 一、OpenGL概述二、着色器基础三、OpenGL绘制方式四、颜色、像素和片元五、视口变换、裁减、剪切与反馈六、纹理与帧缓存七、光照与阴影八、程序式纹理 skip九、细分着色器 skip十、几何着色器 skip十一、内存十二、计算着色器 skip附录 A 第三方支持库附录 B OpenGL …...

C++中常用的十大排序方法之1——冒泡排序

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C中常用的排序方法之——冒泡排序的相关…...

算法总结-哈希表

文章目录 1.赎金信1.答案2.思路 2.字母异位词分组1.答案2.思路 3.两数之和1.答案2.思路 4.快乐数1.答案2.思路 5.最长连续序列1.答案2.思路 1.赎金信 1.答案 package com.sunxiansheng.arithmetic.day14;/*** Description: 383. 赎金信** Author sun* Create 2025/1/22 11:10…...

文件上传功能(一)

总说 过程参考黑马程序员SpringBoot3Vue3全套视频教程&#xff0c;springbootvue企业级全栈开发从基础、实战到面试一套通关_哔哩哔哩_bilibili 目录 总说 一、功能实现 1.1 Controller层 二、优化 一、功能实现 1.1 Controller层 在contoller层&#xff0c;创建一个File…...

【LeetCode 刷题】二叉树-二叉树的属性

此博客为《代码随想录》二叉树章节的学习笔记&#xff0c;主要内容为二叉树的属性相关的题目解析。 文章目录 101. 对称二叉树104.二叉树的最大深度111.二叉树的最小深度222.完全二叉树的节点个数110.平衡二叉树257. 二叉树的所有路径404.左叶子之和513.找树左下角的值112. 路…...

Redisson

Redisson快速入门 将原先逻辑修改 Redis代金卷(优惠卷)秒杀案例-多应用版-CSDN博客...

回顾生化之父三上真司的游戏思想

1. 放养式野蛮成长路线&#xff0c;开创生存恐怖类型 三上进入capcom后&#xff0c;没有培训&#xff0c;没有师傅手把手的指导&#xff0c;而是每天摸索写策划书&#xff0c;老员工给出不行的评语后&#xff0c;扔掉旧的重写新的。 然后突然就成为游戏总监&#xff0c;进入开…...

汽车网络信息安全-ISO/SAE 21434解析(中)

目录 第七章-分布式网络安全活动 1. 供应商能力评估 2. 报价 3. 网络安全职责界定 第八章-持续的网络安全活动 1. 网路安全监控 2. 网络安全事件评估 3. 漏洞分析 4. 漏洞管理 第九章-概念阶段 1. 对象定义 2. 网路安全目标 3. 网络安全概念 第十章 - 产品开发 第十…...

Tailwind CSS - Tailwind CSS 引入(安装、初始化、配置、引入、构建、使用 Tailwind CSS)

一、Tailwind CSS 概述 Tailwind CSS 是一个功能优先的 CSS 框架&#xff0c;它提供了大量的实用类&#xff08;utility classes&#xff09;&#xff0c;允许开发者通过组合这些类来快速构建用户界面 Tailwind CSS 与传统的 CSS 框架不同&#xff08;例如&#xff0c;Bootstr…...

Python-基于PyQt5,pdf2docx,pathlib的PDF转Word工具

前言:日常生活中,我们常常会跟WPS Office打交道。作表格,写报告,写PPT......可以说,我们的生活已经离不开WPS Office了。与此同时,我们在这个过程中也会遇到各种各样的技术阻碍,例如部分软件的PDF转Word需要收取额外费用等。那么,可不可以自己开发一个小工具来实现PDF转…...

FreeRTOS学习 --- 中断管理

什么是中断&#xff1f; 让CPU打断正常运行的程序&#xff0c;转而去处理紧急的事件&#xff08;程序&#xff09;&#xff0c;就叫中断 中断执行机制&#xff0c;可简单概括为三步&#xff1a; 1&#xff0c;中断请求 外设产生中断请求&#xff08;GPIO外部中断、定时器中断…...

【小鱼闪闪】单片机开发工具——米思齐软件下载安装(图文)

浏览器打开网址 mixly.org, 在软件平台选择mixly离线版。 最新版本为3.0&#xff0c;会支持audinio&#xff0c; ESP32、ESP8266 &#xff0c; 可以选择下载安装器或者完整版。 这里选择下载安装器&#xff0c;下载后运行“一键更新.bat”&#xff0c;即可自动下载最新版本的M…...

HarmonyOS:创建应用静态快捷方式

一、前言 静态快捷方式是一种在系统中创建的可以快速访问应用程序或特定功能的链接。它通常可以在长按应用图标&#xff0c;以图标和相应的文字出现在应用图标的上方&#xff0c;用户可以迅速启动对应应用程序的组件。使用快捷方式&#xff0c;可以提高效率&#xff0c;节省了查…...

企业微信远程一直显示正在加载

企业微信远程一直显示正在加载 1.问题描述2.问题解决 系统&#xff1a;Win10 1.问题描述 某天使用企业微信给同事进行远程协助的时候&#xff0c;发现一直卡在正在加载的页面&#xff0c;如下图所示 2.问题解决 经过一番查找资料后&#xff0c;我发现可能是2个地方出了问题…...

FireFox | Google Chrome | Microsoft Edge 禁用更新 final版

之前的方式要么失效&#xff0c;要么对设备有要求&#xff0c;这次梳理一下对设备、环境几乎没有要求的通用方式&#xff0c;universal & final 版。 1.Firefox 方式 FireFox火狐浏览器企业策略禁止更新_火狐浏览器禁止更新-CSDN博客 这应该是目前最好用的方式。火狐也…...

【C++】类和对象(5)

目录 一、构造函数补充1、初始化列表 二、类型转换三、static成员四、友元1、友元函数2、友元类 五、内部类六、匿名对象 一、构造函数补充 对于之前讲解的构造函数&#xff0c;还有一些更深层次的内容要进行补充&#xff0c;接下来进行补充内容的讲解。 1、初始化列表 在我…...

芸众商城小程序会员页面部分图标不显示问题解决办法

我遇到的问题 如下图所示&#xff0c;会员中心这里的图标在小程序端显示异常。但是在网页端又是能够正常显示的。 小程序端截图&#xff1a; 网页端截图&#xff1a; 我的解决方法 检查使用的小程序版本&#xff0c;比如这里使用的是1.2.238版本的小程序&#xff0c;最后…...

Spring Web MVC基础第一篇

目录 1.什么是Spring Web MVC&#xff1f; 2.创建Spring Web MVC项目 3.注解使用 3.1RequestMapping&#xff08;路由映射&#xff09; 3.2一般参数传递 3.3RequestParam&#xff08;参数重命名&#xff09; 3.4RequestBody&#xff08;传递JSON数据&#xff09; 3.5Pa…...

Privacy Eraser,电脑隐私的终极清除者

Privacy Eraser 是一款专为保护用户隐私而设计的全能型软件&#xff0c;它不仅能够深度清理计算机中的各类隐私数据&#xff0c;还提供了多种系统优化工具&#xff0c;帮助用户提升设备的整体性能。通过这款软件&#xff0c;用户可以轻松清除浏览器历史记录、缓存文件、Cookie、…...

编程题-三数之和(中等)

题目&#xff1a; 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。注意&#xff1a;答案中不可以包含重复的三…...

mysql中in和exists的区别?

大家好&#xff0c;我是锋哥。今天分享关于【mysql中in和exists的区别&#xff1f;】面试题。希望对大家有帮助&#xff1b; mysql中in和exists的区别&#xff1f; 在 MySQL 中&#xff0c;IN 和 EXISTS 都是用于子查询的操作符&#xff0c;但它们在执行原理和适用场景上有所不…...

ThinkPHP 8 操作JSON数据

【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 使用VS Code开发ThinkPHP项目-CSDN博客 编程与应用开…...

深入剖析 Docker 的镜像分层存储机制

目录 一、基本原理 镜像构成 UnionFS 二、工作方式 镜像构建时 容器启动时 三、优势 共享与复用 高效存储和传输 快速镜像构建 可追溯性和可维护性 四、相关命令 查看镜像分层 基于已有镜像创建新镜像 Docker 凭借其卓越的性能和极高的灵活性,已然成为众多开发者…...

本地部署DeepSeek

1、打开ollama,点击“Download” Ollamahttps://ollama.com/ 2、下载完成后&#xff0c;安装ollama.exe 3、安装完成后&#xff0c;按"windowsR",输入"cmd” 4、输入“ollama -v”&#xff0c;查看版本&#xff0c;表示安装成功 5、返回ollama网页&#xff0c…...

10.5 LangChain Model I/O 深度解析:如何用标准化接口打通大模型开发的“任督二脉”?

LangChain Model I/O 深度解析:如何用标准化接口打通大模型开发的“任督二脉”? 关键词: LangChain Model I/O、大模型抽象、LLM标准化调用、多模型支持、流式响应 一、为什么需要标准化的大模型抽象? 1. 大模型开发的现实困境 厂商锁定风险:代码深度耦合特定API(如Op…...

使用Pygame制作“俄罗斯方块”游戏

1. 前言 俄罗斯方块&#xff08;Tetris&#xff09; 是一款由方块下落、行消除等核心规则构成的经典益智游戏&#xff1a; 每次从屏幕顶部出现一个随机的方块&#xff08;由若干小方格组成&#xff09;&#xff0c;玩家可以左右移动或旋转该方块&#xff0c;让它合适地堆叠在…...

OSCP:常见文件传输方法

在渗透测试过程中&#xff0c;文件传输是一个关键环节&#xff0c;涉及不同的协议和工具&#xff0c;本文整理了 Linux 和 Windows 系统下常见的文件传输方法&#xff0c;并提供相应的命令示例。 通用文件传输方式 Base64 编码传输 Base64 可用于跨平台传输文件&#xff0c;…...

基于遗传优化GRNN和Hog特征提取的交通标志识别算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 HOG 4.2 GRNN&#xff08;General Regression Neural Network&#xff09;模型原理 4.3 遗传算法&#xff08;GA&#xff09;优化GRNN平滑因子 5.算法完整程序工程 1.算法运行效果图预…...