Serilog 最佳实践

Serilog 最佳实践

概述

Serilog[1]是 Microsoft .NET 的结构化日志记录库,并已成为Checkout.com 上NET 的首选日志记录库。它支持各种日志记录目的地(称为接收器[2])包从标准控制台和基于文件的接收器到日志服务,如 Datadog。

本指南最初是我们工程手册中的一篇文章,在收到内部积极反馈后,我决定在我的博客上发布它。

内容

1.标准日志属性2.日志记录基础知识1.记录一切2.选择合适的日志记录级别3.定时操作源4.上下文5.HTTP 日志记录6.日志的职责3.日志内容的采集1.Serilog标准采集方法2.通过全局属性采集日志4.关联日志5.消息模板1.消息模板推荐6.日志和诊断上下文1.日志上下文2.诊断上下文7.配置8.生产日志1.当日志变得不仅仅是日志9.其他工具和实用程序1.在本地使用 Seq2.按日志类型记录日志3.按属性块记录日志4.按请求记录日志

标准日志属性

标准化日志事件属性使您能够充分利用日志搜索和分析工具。在适用的情况下使用以下属性:

ApplicationName生成日志事件的应用程序的名称
ClientIP发出请求的客户端的 IP 地址
CorrelationId可用于跨多个应用程序边界跟踪请求的 ID
Elapsed操作完成所用的时间(以毫秒为单位)
EventType用于确定消息类型的消息模板的哈希值
MachineName运行应用程序的机器的名称
Outcome手术的结果
RequestMethodHTTP 请求方法,例如 POST
RequestPathHTTP 请求路径
SourceContext日志源自的组件/类的名称
StatusCodeHTTP 响应状态码
UserAgentHTTP 用户代理
Version正在运行的应用程序的版本

上面的很多属性都来自于 Serilog 自己的扩展,例如Serilog Timings[3](用于计时操作)和Serilog 请求日志记录[4]

日志记录基础知识

记录一切

通常,记录所有可以深入了解您的应用程序和用户行为的内容,例如:

•代码中的主要分支点•遇到错误或意外值时•任何 IO 或资源密集型操作•重大领域事件•请求失败和重试•耗时的批处理操作的开始和结束

选择合适的日志记录级别

对您的日志记录要慷慨,但对您的日志记录级别要严格。在几乎所有情况下,您的日志级别都应该是Debug. 使用Information的日志事件,将在生产中需要确定运行状态或应用程序的正确性,WarningError突发事件,如异常。

请注意,该Error级别应保留用于您打算对其采取行动的事件。如果某些事情成为正常的应用程序行为(例如,请求输入验证失败),您应该降级日志级别以减少日志“噪音”。

定时操作

将应用程序中的每个资源密集型操作(例如 IO)与指标代码一起记录下来。这在本地运行应用程序以查看应用程序瓶颈或响应时间消耗的情况时非常有用。该Serilog时序库[5]提供了一个方便的方式来做到这一点:

using (_logger.TimeDebug("Sending notification to Slack channel {Channel} with {WebhookUrl}", _slackOptions.Channel, _slackOptions.WebhookUrl))
using (_metrics.TimeIO("http", "slack", "send_message"))
{}

源上下文

SourceContext属性用于跟踪日志事件的来源,通常是使用记录器的 C# 类。ILogger使用依赖注入将 Serilog 注入到类中是很常见的。为确保SourceContext正确设置,请使用ForContext扩展名:

public TheThing(ILogger logger)
{_logger = logger?.ForContext<TheThing>() ?? throw new ArgumentNullException(nameof(_logger));
}

HTTP 日志记录

使用Serilog 请求日志记录中间件[6]来记录 HTTP 请求。这会自动包含上面列出的许多 HTTP 属性并生成以下日志消息:

HTTP POST /payments responded 201 in 1348.6188 ms

将以下内容添加到您的应用程序启动中以添加中间件:

public void Configure(IApplicationBuilder app)
{app.UseHealthAndMetricsMiddleware();app.UseSerilogRequestLogging();app.UseAuthentication();app.UseMvc();
}

请注意,在health 和 metrics 中间件之后添加了 Serilog中间件。这是为了避免每次 AWS 负载均衡器命中您的健康检查端点时生成日志。

记录 HTTP 资源

Serilog 中间件默认记录请求路径。如果您确实需要查看对应用程序中特定端点的所有请求,如果路径包含标识符等动态参数,您可能会遇到挑战。

为了解决这个问题,记录资源名称,在我们的应用程序中,按照惯例,它是Name赋予相应路由的属性。这是这样检索的:

public static string GetMetricsCurrentResourceName(this HttpContext httpContext)
{if (httpContext == null)throw new ArgumentNullException(nameof(httpContext));Endpoint endpoint = httpContext.Features.Get<IEndpointFeature>()?.Endpoint;#if NETCOREAPP3_1return endpoint?.Metadata.GetMetadata<EndpointNameMetadata>()?.EndpointName;
#elsereturn endpoint?.Metadata.GetMetadata<IRouteValuesAddressMetadata>()?.RouteName;
#endif
}

日志的职责

过度全面的日志记录不仅会对您的应用程序产生性能影响,而且还会使诊断问题变得更加困难,并增加暴露敏感信息的风险。

Serilog 支持结构化对象输出,允许将复杂对象作为日志中的参数传递。这应该谨慎使用,如果您的主要目标是对相关属性进行分组,您最好初始化一个新的匿名对象,这样您就可以明确哪些信息被推送到日志中。

倾向于使用 Serilog 的诊断上下文功能(下面讨论)将日志折叠为单个日志条目。

收集日志

将附加信息推送到您的日志中有助于提供有关特定事件的附加上下文。

标准 Serilog 收集器

您可以使用收集器来丰富应用程序生成的所有日志事件。我们建议使用以下 Serilog 浓缩器:

•日志上下文收集器 - 内置于 Serilog,此丰富器可确保添加到日志上下文的[7]任何属性都被推送到日志事件中•环境收集器[8]- 使用机器或当前用户名采集日志

可以使用Enrich.WithSerilog的fluent APILoggerConfiguration或通过您的appsettings.json文件(推荐)指定增强器:

{"Serilog": {"Using": ["Serilog.Sinks.Console"],"MinimumLevel": {"Default": "Information"},"WriteTo": [{"Name": "Console"}],"Enrich": ["FromLogContext","WithMachineName"],"Properties": {"ApplicationName": "Gateway API"}}
}

全局属性采集

您还可以全局指定属性。上面的片段appsettings.json演示了我们通常如何设置ApplicationName属性。在某些情况下,我们需要在启动时计算属性,这可以使用 Fluent API 来完成:

loggerConfiguration.ReadFrom.Configuration(hostContext.Configuration).EnrichWithEventType().Enrich.WithProperty("Version", ReflectionUtils.GetAssemblyVersion<Program>());

关联日志

为了关联属于同一请求的日志,甚至跨多个应用程序,请CorrelationId向日志添加一个属性。

在 HTTP 应用程序中,我们通常从HttpContext.TraceIdentifier属性映射它。这是使用Cko-Correlation-Id标头在内部 API 之间传递的。我们使用以下扩展来获取 _current_correlation ID:

public static string GetCorrelationId(this HttpContext httpContext)
{httpContext.Request.Headers.TryGetValue("Cko-Correlation-Id", out StringValues correlationId);return correlationId.FirstOrDefault() ?? httpContext.TraceIdentifier;
}

请注意,如果应用程序面向用户,则不应依赖提供的相关 ID 标头。

为了确保将关联 ID 推送到每个日志事件中,我们使用以下使用 Serilog 的中间件LogContext(本文稍后将详细讨论):

public class RequestLogContextMiddleware
{private readonly RequestDelegate _next;public RequestLogContextMiddleware(RequestDelegate next){_next = next;}public Task Invoke(HttpContext context){using (LogContext.PushProperty("CorrelationId", context.GetCorrelationId())){return _next.Invoke(context);}}
}

消息模板

日志消息应提供事件的简短描述。我们通常看到开发人员创建过于冗长的消息作为在事件中包含额外数据的手段,例如:

_logger.Information("Storing payment state in Couchbase for Payment ID {PaymentId} and current state {State}", paymentId, state);

相反,您可以使用ForContext(或本文底部的属性包丰富器)仍然包含数据但具有更简洁的消息:

_logger.ForContext("PaymentId", paymentId).ForContext("State", state).Information("Storing payment state in Couchbase");

消息模板推荐

Fluent风格指南

好的 Serilog 事件使用属性名称作为消息中的内容来提高可读性并使事件更紧凑,例如:

_logger.Information("Processed {@Position} in {Elapsed:000} ms.", position, elapsedMs);

句子与片段

日志事件消息是片段,而不是句子;为了与使用 Serilog 的其他库保持一致,请尽可能避免尾随句点/句号。

模板与消息

Serilog 事件具有关联的消息模板,而不是消息。在内部,Serilog 解析和缓存每个模板(最多固定大小限制)。将日志方法的字符串参数视为消息,如下例所示,会降低性能并消耗缓存内存。例如,避免:

Log.Information("The time is " + DateTime.Now);

而是使用消息属性:

Log.Information("The time is {Now}", DateTime.Now);

除了在日志消息中使用字符串连接/插值的性能开销之外,它还意味着无法计算一致的事件类型(请参阅事件类型丰富器),从而无法找到特定类型的所有日志。

日志和诊断上下文

Serilog 支持两种可用于增强日志的上下文感知功能。

日志上下文

LogContext可用于动态地添加和移除来自周围“执行上下文”性能; 例如,在事务期间写入的所有消息都可能带有该事务的 id,等等。

RequestLogContextMiddleware上面的介绍演示了如何推动CorrelationId请求到LogContext在请求的开始。这可确保该请求中的所有日志都包含该属性。

更多信息可以在Serilog wiki[9]上找到。

诊断上下文

日志记录的一个挑战是上下文并不总是预先知道。例如,在处理 HTTP 请求的过程中,随着我们通过 HTTP 管道(例如了解用户的身份)

获得

额外的上下文。虽然LogContext我们所有人都会在附加信息可用时创建新上下文,但此信息仅在 _subsequent_log 条目中可用。这通常会导致日志数量增加,只是为了捕获有关整个请求或操作的所有信息。

诊断上下文提供了一个执行上下文(类似于LogContext),其优点是可以在其整个生命周期中进行丰富。请求日志中间件然后使用它来丰富最终的“日志完成事件”。这允许我们将许多不同的日志操作折叠为一个日志条目,其中包含来自请求管道中许多点的信息,例如:

SEQ 中的丰富属性

在这里您可以看到,不仅有中间件发出的 HTTP 属性,还有应用程序数据,例如AcquirerIdMerchantNameResponseCode。这些数据点来自请求中的不同点,但通过IDiagnosticContext接口推送到诊断上下文中:

public class HomeController : Controller
{readonly IDiagnosticContext _diagnosticContext;public HomeController(IDiagnosticContext diagnosticContext){_diagnosticContext = diagnosticContext ?? throw new ArgumentNullException(nameof(diagnosticContext));}public IActionResult Index(){// The request completion event will carry this property_diagnosticContext.Set("CatalogLoadTime", 1423);return View();}

在非 HTTP 应用程序中使用诊断上下文

诊断上下文不限于在 ASP.NET Core 中使用。它也可以以与请求日志中间件非常相似的方式在非 HTTP 应用程序中使用。例如,我们使用它在 SQS 使用者中生成完成日志事件。

配置

Serilog 可以使用 Fluent API 或通过 Microsoft 配置系统进行配置。我们建议使用配置系统,因为可以在不发布应用程序新版本的情况下更改日志配置。

为此,添加Serilog.Settings.Configuration[10]包并按如下方式配置 Serilog:

public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).UseSerilog((hostContext, loggerConfiguration) =>{loggerConfiguration.ReadFrom.Configuration(hostContext.Configuration);}).ConfigureAppConfiguration((hostingContext, config) =>{config.AddEnvironmentVariables(prefix: "FLOW_").AddAwsSecrets();}).ConfigureWebHostDefaults(webBuilder =>{webBuilder.UseStartup<Startup>();  });

您现在可以通过任何支持的配置提供程序配置 Serilog。通常我们appsettings.json用于全局设置并通过生产中的环境变量配置实际接收器(因为我们不想在本地运行时使用我们的远程日志服务):

{"Serilog": {"Using": ["Serilog.Sinks.Console","Serilog.Sinks.Datadog.Logs"],"MinimumLevel": {"Default": "Information"},"WriteTo": [{"Name": "Console"}],"Enrich": ["FromLogContext","WithMachineName"],"Properties": {"ApplicationName": "Flow API"}}
}

生产环境下使用日志

在生产中部署应用程序时,请确保相应地配置日志记录:

•控制台日志记录应限于Error. 在 .NET 中,写入控制台是一个阻塞调用,会对性能产生重大影响[11]。•应为Information及以上配置全局日志记录。

据了解,在新项目发布期间,您可能需要更多信息来建立对解决方案的信心或诊断任何预期的初期问题。与其Information为此升级您的日志条目,不如考虑Debug在有限的时间内启用级别。

从开发人员那里听到的一个常见问题是他们如何在运行时动态切换日志级别。虽然这是可能的,但也可以使用蓝/绿部署来实现。使用降低的日志级别配置和部署非活动环境,然后通过加权目标组切换部分或全部流量。

当日志变得不仅仅是日志

日志可以提供对应用程序的大量洞察,并且在许多情况下足以处理日常支持请求或故障排除。然而,在某些情况下,日志可能不能确保你的工作正确,有许多警告信号:

•您发现自己向非技术用户开放应用程序日志•日志用于生成应用程序指标•更多信息被“塞进”日志以满足常见的支持请求或报告要求

在这些情况下,您可能需要为您的产品考虑专用工具。许多团队开发了类似“Inspector”的应用程序,将关键系统和业务数据聚合在一起,以处理可以提供给非技术利益相关者的 BAU 请求。此外,您可能会发现需要将应用程序中的数据推送到报告和分析工具中。

日志的有效性取决于您记录的内容和未记录的内容。

其他工具和实用程序

在本地使用 Seq

Seq[12]是由 Serilog 的作者创建的免费(供本地使用)日志记录工具。它提供高级搜索和过滤功能以及对结构化日志数据的完全访问。虽然我们的日志记录要求现在超出了 Seq 所能提供的范围,但它仍然是本地测试的一个很好的选择。

我们通常在 docker 中启动 Seq 作为单独的 docker-compose 文件 ( docker-compose-logging.hml) 的一部分:

version: "3.5"services:seq:image: datalust/seq:latestcontainer_name: seqports:- '5341:80'environment:- ACCEPT_EULA=Ynetworks:- gateway-networknetworks:
gateway-network:name: gateway-network

并配置我们的appsettings.Development.json文件以使用 Seq 接收器:

{"Serilog": {"Using": ["Serilog.Sinks.Console","Serilog.Sinks.Seq"],"MinimumLevel": {"Default": "Debug","Override": {"Microsoft": "Warning"}},"WriteTo": [{"Name": "Console"},{"Name": "Seq","Args": {"serverUrl": "http://localhost:5341","apiKey": "none"}}]}
}

事件类型收集器

通常我们需要唯一标识相同类型的日志。一些接收器(例如Seq)[13]通过散列消息模板来自动执行此操作。为了在其他接收器中复制相同的行为,我们创建了以下使用Murmerhash 算法[14]的收集器[15]

internal class EventTypeEnricher : ILogEventEnricher
{public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory){if (logEvent is null)throw new ArgumentNullException(nameof(logEvent));if (propertyFactory is null)throw new ArgumentNullException(nameof(propertyFactory));Murmur32 murmur = MurmurHash.Create32();byte[] bytes = Encoding.UTF8.GetBytes(logEvent.MessageTemplate.Text);byte[] hash = murmur.ComputeHash(bytes);string hexadecimalHash = BitConverter.ToString(hash).Replace("-", "");LogEventProperty eventId = propertyFactory.CreateProperty("EventType", hexadecimalHash);logEvent.AddPropertyIfAbsent(eventId);}
}

属性包收集器

如果您想向日志事件添加多个属性,请使用PropertyBagEnricher

public class PropertyBagEnricher : ILogEventEnricher
{private readonly Dictionary<string, Tuple<object, bool>> _properties;/// <summary>/// Creates a new <see cref="PropertyBagEnricher" /> instance./// </summary>public PropertyBagEnricher(){_properties = new Dictionary<string, Tuple<object, bool>>(StringComparer.OrdinalIgnoreCase);}/// <summary>/// Enriches the <paramref name="logEvent" /> using the values from the property bag./// </summary>/// <param name="logEvent">The log event to enrich.</param>/// <param name="propertyFactory">The factory used to create the property.</param>public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory){foreach (KeyValuePair<string, Tuple<object, bool>> prop in _properties){logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(prop.Key, prop.Value.Item1, prop.Value.Item2));}}/// <summary>/// Add a property that will be added to all log events enriched by this enricher./// </summary>/// <param name="key">The property key.</param>/// <param name="value">The property value.</param>/// <param name="destructureObject">/// Whether to destructure the value. See https://github.com/serilog/serilog/wiki/Structured-Data/// </param>/// <returns>The enricher instance, for chaining Add operations together.</returns>public PropertyBagEnricher Add(string key, object value, bool destructureObject = false){if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));if (!_properties.ContainsKey(key)) _properties.Add(key, Tuple.Create(value, destructureObject));return this;}
}

用法:

_logger.ForContext(new PropertyBagEnricher().Add("ResponseCode", response?.ResponseCode).Add("EnrollmentStatus", response?.Enrolled)).Warning("Malfunction when processing 3DS enrollment verification");

收集请求日志

Serilog 请求日志记录中间件允许提供一个函数,该函数可用于将来自 HTTP 请求的附加信息添加到完成日志事件。我们使用它来记录ClientIP,UserAgentResource属性:

public static class LogEnricher
{/// <summary>/// Enriches the HTTP request log with additional data via the Diagnostic Context/// </summary>/// <param name="diagnosticContext">The Serilog diagnostic context</param>/// <param name="httpContext">The current HTTP Context</param>public static void EnrichFromRequest(IDiagnosticContext diagnosticContext, HttpContext httpContext){diagnosticContext.Set("ClientIP", httpContext.Connection.RemoteIpAddress.ToString());diagnosticContext.Set("UserAgent", httpContext.Request.Headers["User-Agent"].FirstOrDefault());diagnosticContext.Set("Resource", httpContext.GetMetricsCurrentResourceName());}
}

用法

app.UseSerilogRequestLogging(opts=> opts.EnrichDiagnosticContext = LogEnricher.EnrichFromRequest);

© 2021 Ben Foster https://benfoster.io/

References

[1] Serilog: https://serilog.net/
[2] 接收器: https://github.com/serilog?q=sinks&type=&language=
[3] Serilog Timings: https://github.com/nblumhardt/serilog-timings
[4] Serilog 请求日志记录: https://github.com/serilog/serilog-aspnetcore
[5] Serilog时序库: https://github.com/nblumhardt/serilog-timings
[6] Serilog 请求日志记录中间件: https://github.com/serilog/serilog-aspnetcore
[7] 日志上下文的: https://github.com/serilog/serilog/wiki/Enrichment
[8] 环境收集器: https://github.com/serilog/serilog-enrichers-environment
[9] Serilog wiki: https://github.com/serilog/serilog/wiki/Enrichment#the-logcontext
[10] Serilog.Settings.Configuration: https://github.com/serilog/serilog-settings-configuration
[11] 性能产生重大影响: https://weblog.west-wind.com/posts/2018/Dec/31/Dont-let-ASPNET-Core-Default-Console-Logging-Slow-your-App-down
[12] Seq: https://datalust.co/seq
[13] Seq): https://datalust.co/seq
[14] Murmerhash 算法: https://github.com/darrenkopp/murmurhash-net
[15] 收集器: https://github.com/darrenkopp/murmurhash-net

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

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

相关文章

世界上迄今为止最安全的加密算法

全世界只有3.14 % 的人关注了青少年数学之旅一个只能用算力来破解的加密算法1人类的加密史公元前5世纪&#xff0c;古希腊人使用一根叫scytale的棍子来传递加密信息。要加密时&#xff0c;先绕棍子卷一张纸条&#xff0c;把信息沿棒水平方向写&#xff0c;写一个字旋转一下&…

手把手教你java快速过滤关键词

java过滤关键词 敏感词、文字过滤是一个网站必不可少的功能&#xff0c;如何设计一个好的、高效的过滤算法是非常有必要的。前段时间我一个朋友&#xff08;马上毕业&#xff0c;接触编程不久&#xff09;要我帮他看一个文字过滤的东西&#xff0c;它说检索效率非常慢。我把它程…

[Delphi]根据输入日期按年月周日输出日期段

输入变量ADateStart&#xff0c;并为其填写起始日期&#xff0c;变量ADateEnd&#xff0c;计算类型AType&#xff0c;输出变量ADateStart&#xff0c;变量ADateEnd procedureFormatDateByType(AType:Integer; varADateStart, ADateEnd: TDate); var//type0日 1周 2月 3年 …

TIOBE 发布 8 月编程语言榜单:C# 排名如何?

刚刚 TIOBE 官方最新发布了 8 月的编程语言榜单&#xff0c;一起来看本月榜单中有什么值得关注的发展趋势吧&#xff1f;每一种编程语言的兴起从来都离不开它所适用的技术领域&#xff0c;二者之间一直以来都是水涨船高的关系。数据挖掘和人工智能的蓬勃发展也是如此&#xff0…

两年了,你还是那个你 | 今日最佳

全世界只有3.14 % 的人关注了青少年数学之旅&#xff08;图源都市音酱&#xff0c;侵权删&#xff09;

k8s入门你至少需要会哪些

前言相信很多公司都有集成发布pass系统&#xff0c;底层大多数依赖于k8s来进行服务的发布部署/回滚等功能。对于很多业务开发者都是不可见的&#xff0c;在感叹这个东西真好用的同时&#xff0c;想着探一探这背后的原理。今天这篇k8s入门我整理了必会的几个k8s知识点&#xff0…

Windows CE的电源管理之三

本篇将以Windows Mobile为例介绍Windows CE电源管理的实现&#xff0c;大体上&#xff0c;Windows Mobile分为Pocket PC和Smartphone两种版本。这两者之间的主要区别在于触摸屏和电源模型&#xff0c;Smartphone采用的是“Always On”模型。为了说清楚它们的区别&#xff0c;我…

跟你们讲一个鬼故事,TA回来了!

全世界只有3.14 % 的人关注了青少年数学之旅真正决定人与人之间的差距的&#xff0c;其实是我们对事物的见识与内心的格局&#xff0c;见识的深浅决定人生的深浅&#xff0c;格局的大小决定了人生之路是宽是窄。今天给大家推荐几个有深度、有想法的公众号&#xff0c;希望能够给…

java之static关键词的作用

static关键词的作用 1、静态成员变量的语法特定 2、静态函数的语法特定 3、静态代码块的语法特定 定义静态成员变量 Person.java class Person{ static int a; }按照以前可以这么调用 public class Test1{ public static void main(String[] args){ Person person new Per…

分布式事务最终一致性-CAP框架轻松搞定

前言对于分布式事务&#xff0c;常用的解决方案根据一致性的程度可以进行如下划分&#xff1a;强一致性(2PC、3PC)&#xff1a;数据库层面的实现&#xff0c;通过锁定资源&#xff0c;牺牲可用性&#xff0c;保证数据的强一致性&#xff0c;效率相对比较低。弱一致性(TCC)&…

Cus系统beta1.2发布

2019独角兽企业重金招聘Python工程师标准>>> 经过小伙伴的努力&#xff0c;Cus后台管理系统开发完成&#xff0c;完善了后台系统&#xff0c;权限控制&#xff0c;新闻发布&#xff0c;商务合作等等功能 主要功能包括&#xff1a; 后台系统截图 更多后台系统截图请点…

区区6位密码,凭什么守护我的百万家产?

全世界只有3.14 % 的人关注了青少年数学之旅今天超模君非常的开心你问为什么&#xff1f;当然是——又双叒可以买新的数学书好开心&#xff01;不过在这欢快的气氛中超模君却听见了小天的叹气声玩笑归玩笑但是银行的密码系统真很安全的吗&#xff1f;今天我们就来讨论下密码学的…

Java开发之上班摸鱼!写最少的代码!

I 前言 本次分享一下我所知道的如何写最少的代码的小技巧&#xff0c;如果你有更好的方案&#xff0c;欢迎在评论区留言&#xff0c;方案很棒的话&#xff0c;加我交流圈&#xff0c;为你送上冬天的一杯奶茶~ Java&#xff1a;我想返回多个返回值 秀一下Go的多返回值&#xf…

Windows 11 预览版 Build 22000.120 发布

微软现已发布第五个 Windows 11 预览版更新 KB5005188&#xff0c;版本号升级至 Build 22000.120。本次更新面向 Dev 频道和 Beta 频道的 Windows 预览体验成员推出。Windows 11 Insider Preview Build 22000.120 主要变化如下&#xff1a;1.全新的 Family Safety&#xff08;家…

robocopy帮助

一 Robocopy简介 Robocopy 是一个功能超强的32位的文件复制工具&#xff0c;该工具来自windows资源包&#xff0c;可以直接在网上下载。 使用Robocopy你能够拷贝单个目录&#xff0c;或迭代的拷贝目录及其所有的子目录。该工具通过文件是否存在于源目录&#xff0c;目标目录&am…

有趣的灵魂连墓碑都很酷! | 今日趣图

全世界只有3.14 % 的人关注了青少年数学之旅&#xff08;图源别是个沙雕吧&#xff0c;侵权删&#xff09;

实施Exchange 2013中的 MailTip

实施Exchange 2013中的 MailTip邮件提示是用户撰写邮件时向其显示的提示性消息。Microsoft Exchange Server 2013 将分析邮件&#xff08;包括向其发送了邮件的收件人的列表&#xff09;&#xff0c;如果检测到潜在问题&#xff0c;它将使用邮件提示在邮件发送之前通知用户。借…

防弹玻璃为啥会被钢球砸碎?这就是一道高中物理题!

全世界只有3.14 % 的人关注了青少年数学之旅马斯克&#xff0c;硅谷钢铁侠&#xff0c;全世界最具煽动力的企业家。旗下公司特斯拉最新电动皮卡&#xff0c;一经亮相就欢呼一片&#xff0c;传播到炸&#xff0c;看起来又要重新定义一个品类。然而也有网友“提醒”——如今的马斯…

八种ADSL接入情况中断流现象分析

转载自&#xff1a;网盟技术[url]http://technic.txwm.com[/url] 线路不稳定 如果住所离电信局太远(5公里以上)可以向电信部门申报。确保线路连接正确(不同的话音分离器的连接方法有所不同&#xff0c;请务必按照说明书指引正确连接)。同时确保线路通讯质量良好没有被干扰&…

Java之jdk与jre的区别

很多程序员已经干了一段时间java了依然不明白jdk与jre的区别。 JDK就是Java Development Kit.简单的说JDK是面向开发人员使用的SDK&#xff0c;它提供了Java的开发环境和运行环境。SDK是Software Development Kit 一般指软件开发包&#xff0c;可以包括函数库、编译程序等。 …