{"id":623,"date":"2025-04-05T11:42:56","date_gmt":"2025-04-05T03:42:56","guid":{"rendered":"https:\/\/www.hyy.net\/?p=623"},"modified":"2025-04-05T11:42:56","modified_gmt":"2025-04-05T03:42:56","slug":"asp-net-core-in-action-26-monitoring-and-troubleshooting-errors-with-logging","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=623","title":{"rendered":"ASP.NET Core in Action 26 Monitoring and troubleshooting errors with logging"},"content":{"rendered":"<p>26 Monitoring and troubleshooting errors with logging<br \/>\n26 \u4f7f\u7528\u65e5\u5fd7\u8bb0\u5f55\u76d1\u63a7\u548c\u6392\u9664\u9519\u8bef<\/p>\n<p>This chapter covers<br \/>\n\u672c\u7ae0\u6db5\u76d6<\/p>\n<p>\u2022  Understanding the components of a log message<br \/>\n\u4e86\u89e3\u65e5\u5fd7\u6d88\u606f\u7684\u7ec4\u6210\u90e8\u5206<\/p>\n<p>\u2022  Writing logs to multiple output locations<br \/>\n\u5c06\u65e5\u5fd7\u5199\u5165\u591a\u4e2a\u8f93\u51fa\u4f4d\u7f6e<\/p>\n<p>\u2022  Controlling log verbosity in different environments using filtering<br \/>\n\u4f7f\u7528\u7b5b\u9009\u63a7\u5236\u4e0d\u540c\u73af\u5883\u4e2d\u7684\u65e5\u5fd7\u8be6\u7ec6\u7a0b\u5ea6<\/p>\n<p>\u2022  Using structured logging to make logs searchable<br \/>\n\u4f7f\u7528\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u4f7f\u65e5\u5fd7\u53ef\u641c\u7d22<\/p>\n<p>Logging is one of those topics that seems unnecessary, right up until you desperately need it! There\u2019s nothing more frustrating than finding a problem that you can reproduce only in production and then discovering there are no logs to help you debug it.<br \/>\n\u65e5\u5fd7\u8bb0\u5f55\u662f\u90a3\u4e9b\u4f3c\u4e4e\u4e0d\u5fc5\u8981\u7684\u4e3b\u9898\u4e4b\u4e00\uff0c\u76f4\u5230\u60a8\u8feb\u5207\u9700\u8981\u5b83\u4e3a\u6b62\uff01\u6ca1\u6709\u4ec0\u4e48\u6bd4\u627e\u5230\u53ea\u80fd\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u91cd\u73b0\u7684\u95ee\u9898\uff0c\u7136\u540e\u53d1\u73b0\u6ca1\u6709\u65e5\u5fd7\u53ef\u4ee5\u5e2e\u52a9\u60a8\u8c03\u8bd5\u5b83\u66f4\u4ee4\u4eba\u6cae\u4e27\u7684\u4e86\u3002<\/p>\n<p>Logging is the process of recording events or activities in an app, and it often involves writing a record to a console, a file, the Windows Event Log, or some other system. You can record anything in a log message, though there are generally two different types of messages:<br \/>\n\u65e5\u5fd7\u8bb0\u5f55\u662f\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u8bb0\u5f55\u4e8b\u4ef6\u6216\u6d3b\u52a8\u7684\u8fc7\u7a0b\uff0c\u5b83\u901a\u5e38\u6d89\u53ca\u5c06\u8bb0\u5f55\u5199\u5165\u63a7\u5236\u53f0\u3001\u6587\u4ef6\u3001Windows \u4e8b\u4ef6\u65e5\u5fd7\u6216\u5176\u4ed6\u7cfb\u7edf\u3002\u60a8\u53ef\u4ee5\u5728\u65e5\u5fd7\u6d88\u606f\u4e2d\u8bb0\u5f55\u4efb\u4f55\u5185\u5bb9\uff0c\u4f46\u901a\u5e38\u6709\u4e24\u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u6d88\u606f\uff1a<\/p>\n<p>\u2022  Informational messages\u2014A standard event occurred: a user logged in, a product was placed in a shopping cart, or a new post was created on a blogging app.<br \/>\n\u4fe1\u606f\u6027\u6d88\u606f - \u53d1\u751f\u6807\u51c6\u4e8b\u4ef6\uff1a\u7528\u6237\u767b\u5f55\u3001\u4ea7\u54c1\u653e\u5165\u8d2d\u7269\u8f66\u6216\u5728\u535a\u5ba2\u5e94\u7528\u7a0b\u5e8f\u4e0a\u521b\u5efa\u65b0\u5e16\u5b50\u3002<\/p>\n<p>\u2022  Warnings and errors\u2014An error or unexpected condition occurred: a user had a negative total in the shopping cart, or an exception occurred.<br \/>\n\u8b66\u544a\u548c\u9519\u8bef - \u53d1\u751f\u9519\u8bef\u6216\u610f\u5916\u60c5\u51b5\uff1a\u7528\u6237\u8d2d\u7269\u8f66\u4e2d\u7684\u603b\u6570\u4e3a\u8d1f\u6570\uff0c\u6216\u53d1\u751f\u5f02\u5e38\u3002<\/p>\n<p>Historically, a common problem with logging in larger applications was that each library and framework would generate logs in a slightly different format, if at all. When an error occurred in your app and you were trying to diagnose it, this inconsistency made it harder to connect the dots in your app to get the full picture and understand the problem.<br \/>\n\u4ece\u5386\u53f2\u4e0a\u770b\uff0c\u5728\u5927\u578b\u5e94\u7528\u7a0b\u5e8f\u4e2d\u767b\u5f55\u7684\u4e00\u4e2a\u5e38\u89c1\u95ee\u9898\u662f\uff0c\u6bcf\u4e2a\u5e93\u548c\u6846\u67b6\u90fd\u4f1a\u4ee5\u7565\u6709\u4e0d\u540c\u7684\u683c\u5f0f\u751f\u6210\u65e5\u5fd7\uff08\u5982\u679c\u6709\u7684\u8bdd\uff09\u3002\u5f53\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u53d1\u751f\u9519\u8bef\u5e76\u4e14\u60a8\u5c1d\u8bd5\u8bca\u65ad\u5b83\u65f6\uff0c\u8fd9\u79cd\u4e0d\u4e00\u81f4\u4f7f\u5f97\u60a8\u66f4\u96be\u5c06\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u5404\u4e2a\u70b9\u8fde\u63a5\u8d77\u6765\u4ee5\u83b7\u5f97\u5b8c\u6574\u7684\u56fe\u7247\u5e76\u4e86\u89e3\u95ee\u9898\u3002<\/p>\n<p>Luckily, ASP.NET Core includes a new generic logging interface that you can plug into. It\u2019s used throughout the ASP.NET Core framework code itself, as well as by third-party libraries, and you can easily use it to create logs in your own code. With the ASP.NET Core logging framework, you can control the verbosity of logs coming from each part of your code, including the framework and libraries, and you can write the log output to any destination that plugs into the framework.<br \/>\n\u5e78\u8fd0\u7684\u662f\uff0cASP.NET Core \u5305\u542b\u4e00\u4e2a\u53ef\u4ee5\u63d2\u5165\u7684\u65b0\u901a\u7528\u65e5\u5fd7\u8bb0\u5f55\u63a5\u53e3\u3002\u5b83\u5728\u6574\u4e2a ASP.NET Core \u6846\u67b6\u4ee3\u7801\u672c\u8eab\u4ee5\u53ca\u7b2c\u4e09\u65b9\u5e93\u4e2d\u4f7f\u7528\uff0c\u60a8\u53ef\u4ee5\u8f7b\u677e\u5730\u4f7f\u7528\u5b83\u5728\u81ea\u5df1\u7684\u4ee3\u7801\u4e2d\u521b\u5efa\u65e5\u5fd7\u3002\u4f7f\u7528 ASP.NET Core \u65e5\u5fd7\u8bb0\u5f55\u6846\u67b6\uff0c\u60a8\u53ef\u4ee5\u63a7\u5236\u6765\u81ea\u4ee3\u7801\u6bcf\u4e2a\u90e8\u5206\uff08\u5305\u62ec\u6846\u67b6\u548c\u5e93\uff09\u7684\u65e5\u5fd7\u7684\u8be6\u7ec6\u7a0b\u5ea6\uff0c\u5e76\u4e14\u53ef\u4ee5\u5c06\u65e5\u5fd7\u8f93\u51fa\u5199\u5165\u63d2\u5165\u6846\u67b6\u7684\u4efb\u4f55\u76ee\u6807\u3002<\/p>\n<p>In this chapter I cover the .NET logging framework ASP.NET Core uses in detail, and I explain how you can use it to record events and diagnose errors in your own apps. In section 26.1 I\u2019ll describe the architecture of the logging framework. You\u2019ll learn how dependency injection (DI) makes it easy for both libraries and apps to create log messages, as well as to write those logs to multiple destinations.<br \/>\n\u5728\u672c\u7ae0\u4e2d\uff0c\u6211\u5c06\u8be6\u7ec6\u4ecb\u7ecd Core \u4f7f\u7528\u7684 .NET \u65e5\u5fd7\u8bb0\u5f55\u6846\u67b6 ASP.NET \u5e76\u8bf4\u660e\u5982\u4f55\u4f7f\u7528\u5b83\u6765\u8bb0\u5f55\u4e8b\u4ef6\u548c\u8bca\u65ad\u60a8\u81ea\u5df1\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u9519\u8bef\u3002\u5728 Section 26.1 \u4e2d\uff0c\u6211\u5c06\u63cf\u8ff0 logging \u6846\u67b6\u7684\u67b6\u6784\u3002\u60a8\u5c06\u4e86\u89e3\u4f9d\u8d56\u5173\u7cfb\u6ce8\u5165 \uff08DI\uff09 \u5982\u4f55\u4f7f\u5e93\u548c\u5e94\u7528\u7a0b\u5e8f\u8f7b\u677e\u521b\u5efa\u65e5\u5fd7\u6d88\u606f\uff0c\u4ee5\u53ca\u5c06\u8fd9\u4e9b\u65e5\u5fd7\u5199\u5165\u591a\u4e2a\u76ee\u6807\u3002<\/p>\n<p>In section 26.2 you\u2019ll learn how to write your own log messages in your apps with the ILogger interface. We\u2019ll break down the anatomy of a typical log record and look at its properties, such as the log level, category, and message.<br \/>\n\u5728\u7b2c 26.2 \u8282\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4f7f\u7528 ILogger \u63a5\u53e3\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7f16\u5199\u81ea\u5df1\u7684\u65e5\u5fd7\u6d88\u606f\u3002\u6211\u4eec\u5c06\u5206\u89e3\u5178\u578b\u65e5\u5fd7\u8bb0\u5f55\u7684\u5256\u6790\uff0c\u5e76\u67e5\u770b\u5176\u5c5e\u6027\uff0c\u4f8b\u5982\u65e5\u5fd7\u7ea7\u522b\u3001\u7c7b\u522b\u548c\u6d88\u606f\u3002<\/p>\n<p>Writing logs is useful only if you can read them, so in section 26.3 you\u2019ll learn how to add logging providers to your application. Logging providers control where your app writes your log messages, such as to the console, to a file, or even to an external service.<br \/>\n\u53ea\u6709\u5f53\u60a8\u53ef\u4ee5\u9605\u8bfb\u65e5\u5fd7\u65f6\uff0c\u7f16\u5199\u65e5\u5fd7\u624d\u6709\u7528\uff0c\u56e0\u6b64\u5728 Section 26.3 \u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u5c06\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u3002\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u63a7\u5236\u5e94\u7528\u7a0b\u5e8f\u5c06\u65e5\u5fd7\u6d88\u606f\u5199\u5165\u4f55\u5904\uff0c\u4f8b\u5982\u5199\u5165\u63a7\u5236\u53f0\u3001\u6587\u4ef6\u751a\u81f3\u5916\u90e8\u670d\u52a1\u3002<\/p>\n<p>Logging is an important part of any application, but determining how much logging is enough can be a tricky question. On one hand, you want to provide sufficient information to be able to diagnose any problems. On the other hand, you don\u2019t want to fill your logs with data that makes it hard to find the important information when you need it. Even worse, what is sufficient in development might be far too much once you\u2019re running in production.<br \/>\n\u65e5\u5fd7\u8bb0\u5f55\u662f\u4efb\u4f55\u5e94\u7528\u7a0b\u5e8f\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\uff0c\u4f46\u786e\u5b9a\u591a\u5c11\u65e5\u5fd7\u8bb0\u5f55\u5c31\u8db3\u591f\u4e86\u53ef\u80fd\u662f\u4e00\u4e2a\u68d8\u624b\u7684\u95ee\u9898\u3002\u4e00\u65b9\u9762\uff0c\u60a8\u5e0c\u671b\u63d0\u4f9b\u8db3\u591f\u7684\u4fe1\u606f\u4ee5\u4fbf\u80fd\u591f\u8bca\u65ad\u4efb\u4f55\u95ee\u9898\u3002\u53e6\u4e00\u65b9\u9762\uff0c\u60a8\u4e0d\u5e0c\u671b\u5728\u65e5\u5fd7\u4e2d\u586b\u5145\u6570\u636e\uff0c\u4ece\u800c\u5728\u9700\u8981\u65f6\u96be\u4ee5\u627e\u5230\u91cd\u8981\u4fe1\u606f\u3002\u66f4\u7cdf\u7cd5\u7684\u662f\uff0c\u4e00\u65e6\u4f60\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u8fd0\u884c\uff0c\u5f00\u53d1\u4e2d\u8db3\u591f\u7684\u8d44\u6e90\u53ef\u80fd\u5c31\u592a\u591a\u4e86\u3002<\/p>\n<p>In section 26.4 I\u2019ll explain how you can filter log messages from various sections of your app, such as the ASP.NET Core infrastructure libraries, so that your logging providers write only the important messages. This lets you keep that balance between extensive logging in development and writing only important logs in production.<br \/>\n\u5728 Section 26.4 \u4e2d\uff0c\u6211\u5c06\u89e3\u91ca\u5982\u4f55\u8fc7\u6ee4\u6765\u81ea\u5e94\u7528\u7a0b\u5e8f\u5404\u4e2a\u90e8\u5206\u7684\u65e5\u5fd7\u6d88\u606f\uff0c\u4f8b\u5982 ASP.NET Core \u57fa\u7840\u8bbe\u65bd\u5e93\uff0c\u4ee5\u4fbf\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u4ec5\u5199\u5165\u91cd\u8981\u6d88\u606f\u3002\u8fd9\u4f7f\u60a8\u53ef\u4ee5\u5728 development \u4e2d\u7684\u5927\u91cf\u65e5\u5fd7\u8bb0\u5f55\u548c\u5728 production \u4e2d\u4ec5\u5199\u5165\u91cd\u8981\u65e5\u5fd7\u4e4b\u95f4\u4fdd\u6301\u5e73\u8861\u3002<\/p>\n<p>In the final section of this chapter I\u2019ll touch on some of the benefits of structured logging, an approach to logging that you can use with some providers for the ASP.NET Core logging framework. Structured logging involves attaching data to log messages as key-value pairs to make it easier to search and query logs. You might attach a unique customer ID to every log message generated by your app, for example. Finding all the log messages associated with a user is much simpler with this approach, compared with recording the customer ID in an inconsistent manner as part of the log message.<br \/>\n\u5728\u672c\u7ae0\u7684\u6700\u540e\u4e00\u8282\u4e2d\uff0c\u6211\u5c06\u4ecb\u7ecd\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u7684\u4e00\u4e9b\u597d\u5904\uff0c\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u662f\u4e00\u79cd\u65e5\u5fd7\u8bb0\u5f55\u65b9\u6cd5\uff0c\u60a8\u53ef\u4ee5\u5c06\u5176\u4e0e ASP.NET Core \u65e5\u5fd7\u8bb0\u5f55\u6846\u67b6\u7684\u67d0\u4e9b\u63d0\u4f9b\u7a0b\u5e8f\u4e00\u8d77\u4f7f\u7528\u3002\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u6d89\u53ca\u5c06\u6570\u636e\u4f5c\u4e3a\u952e\u503c\u5bf9\u9644\u52a0\u5230\u65e5\u5fd7\u6d88\u606f\u4e2d\uff0c\u4ee5\u4fbf\u66f4\u8f7b\u677e\u5730\u641c\u7d22\u548c\u67e5\u8be2\u65e5\u5fd7\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u5c06\u552f\u4e00\u7684\u5ba2\u6237 ID \u9644\u52a0\u5230\u5e94\u7528\u7a0b\u5e8f\u751f\u6210\u7684\u6bcf\u6761\u65e5\u5fd7\u6d88\u606f\u4e2d\u3002\u4e0e\u4ee5\u4e0d\u4e00\u81f4\u7684\u65b9\u5f0f\u5c06\u5ba2\u6237 ID \u8bb0\u5f55\u4e3a\u65e5\u5fd7\u6d88\u606f\u7684\u4e00\u90e8\u5206\u76f8\u6bd4\uff0c\u4f7f\u7528\u6b64\u65b9\u6cd5\u67e5\u627e\u4e0e\u7528\u6237\u5173\u8054\u7684\u6240\u6709\u65e5\u5fd7\u6d88\u606f\u8981\u7b80\u5355\u5f97\u591a\u3002<\/p>\n<p>We\u2019ll start this chapter by digging into what logging involves and why your future self will thank you for using logging effectively in your application. Then we\u2019ll look at the pieces of the ASP.NET Core logging framework you\u2019ll use directly in your apps and how they fit together.<br \/>\n\u5728\u672c\u7ae0\u5f00\u59cb\u65f6\uff0c\u6211\u4eec\u5c06\u6df1\u5165\u7814\u7a76\u65e5\u5fd7\u8bb0\u5f55\u6d89\u53ca\u4ec0\u4e48\uff0c\u4ee5\u53ca\u4e3a\u4ec0\u4e48\u672a\u6765\u7684\u81ea\u5df1\u4f1a\u611f\u8c22\u60a8\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u6709\u6548\u5730\u4f7f\u7528\u65e5\u5fd7\u8bb0\u5f55\u3002\u7136\u540e\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u60a8\u5c06\u76f4\u63a5\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u4f7f\u7528\u7684 ASP.NET Core \u65e5\u5fd7\u8bb0\u5f55\u6846\u67b6\u7684\u5404\u4e2a\u90e8\u5206\uff0c\u4ee5\u53ca\u5b83\u4eec\u5982\u4f55\u7ec4\u5408\u5728\u4e00\u8d77\u3002<\/p>\n<h2>26.1 Using logging effectively in a production app<\/h2>\n<p>26.1 \u5728 \u751f\u4ea7\u5e94\u7528\u7a0b\u5e8f\u4e2d\u6709\u6548\u5730\u4f7f\u7528\u65e5\u5fd7\u8bb0\u5f55<\/p>\n<p>Imagine you\u2019ve just deployed a new app to production when a customer calls saying that they\u2019re getting an error message using your app. How would you identify what caused the problem? You could ask the customer what steps they were taking and potentially try to re-create the error yourself, but if that doesn\u2019t work, you\u2019re left trawling through the code, trying to spot errors with nothing else to go on.<br \/>\n\u5047\u8bbe\u60a8\u521a\u521a\u5c06\u4e00\u4e2a\u65b0\u5e94\u7528\u7a0b\u5e8f\u90e8\u7f72\u5230\u751f\u4ea7\u73af\u5883\u4e2d\uff0c\u8fd9\u65f6\u5ba2\u6237\u6253\u7535\u8bdd\u8bf4\u4ed6\u4eec\u5728\u4f7f\u7528\u60a8\u7684\u5e94\u7528\u65f6\u6536\u5230\u4e86\u4e00\u6761\u9519\u8bef\u6d88\u606f\u3002\u60a8\u5c06\u5982\u4f55\u786e\u5b9a\u5bfc\u81f4\u95ee\u9898\u7684\u539f\u56e0\uff1f\u60a8\u53ef\u4ee5\u8be2\u95ee\u5ba2\u6237\u4ed6\u4eec\u6b63\u5728\u91c7\u53d6\u54ea\u4e9b\u6b65\u9aa4\uff0c\u5e76\u53ef\u80fd\u5c1d\u8bd5\u81ea\u5df1\u91cd\u65b0\u521b\u5efa\u9519\u8bef\uff0c\u4f46\u5982\u679c\u8fd9\u4e0d\u8d77\u4f5c\u7528\uff0c\u60a8\u5c31\u53ea\u80fd\u6d4f\u89c8\u4ee3\u7801\uff0c\u8bd5\u56fe\u53d1\u73b0\u9519\u8bef\uff0c\u800c\u6ca1\u6709\u5176\u4ed6\u4e8b\u60c5\u53ef\u505a\u3002<\/p>\n<p>Logging can provide the extra context you need to quickly diagnose a problem. Arguably, the most important logs capture the details about the error itself, but the events that led to the error can be equally useful in diagnosing the cause of an error.<br \/>\n\u65e5\u5fd7\u8bb0\u5f55\u53ef\u4ee5\u63d0\u4f9b\u5feb\u901f\u8bca\u65ad\u95ee\u9898\u6240\u9700\u7684\u989d\u5916\u4e0a\u4e0b\u6587\u3002\u53ef\u4ee5\u8bf4\uff0c\u6700\u91cd\u8981\u7684\u65e5\u5fd7\u6355\u83b7\u4e86\u6709\u5173\u9519\u8bef\u672c\u8eab\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u4f46\u5bfc\u81f4\u9519\u8bef\u7684\u4e8b\u4ef6\u5728\u8bca\u65ad\u9519\u8bef\u539f\u56e0\u65b9\u9762\u540c\u6837\u6709\u7528\u3002<\/p>\n<p>There are many reasons for adding logging to an application, but typically, the reasons fall into one of three categories:<br \/>\n\u5411\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u65e5\u5fd7\u8bb0\u5f55\u7684\u539f\u56e0\u6709\u5f88\u591a\uff0c\u4f46\u901a\u5e38\uff0c\u539f\u56e0\u5206\u4e3a\u4ee5\u4e0b\u4e09\u7c7b\u4e4b\u4e00\uff1a<\/p>\n<p>\u2022  Logging for auditing or analytics reasons, to trace when events have occurred<br \/>\n\u51fa\u4e8e\u5ba1\u6838\u6216\u5206\u6790\u539f\u56e0\u8fdb\u884c\u65e5\u5fd7\u8bb0\u5f55\uff0c\u4ee5\u8ddf\u8e2a\u4e8b\u4ef6\u53d1\u751f\u7684\u65f6\u95f4<\/p>\n<p>\u2022  Logging errors<br \/>\n\u8bb0\u5f55\u9519\u8bef<\/p>\n<p>\u2022  Logging nonerror events to provide a breadcrumb trail of events when an error does occur<br \/>\n\u8bb0\u5f55\u975e\u9519\u8bef\u4e8b\u4ef6\uff0c\u4ee5\u4fbf\u5728\u53d1\u751f\u9519\u8bef\u65f6\u63d0\u4f9b\u4e8b\u4ef6\u7684\u75d5\u8ff9\u5bfc\u822a\u8ddf\u8e2a<\/p>\n<p>The first of these reasons is simple. You may be required to keep a record of every time a user logs in, for example, or you may want to keep track of how many times a particular API method is called. Logging is an easy way to record the behavior of your app by writing a message to the log every time an interesting event occurs.<br \/>\n\u7b2c\u4e00\u4e2a\u539f\u56e0\u5f88\u7b80\u5355\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u80fd\u9700\u8981\u4fdd\u7559\u7528\u6237\u6bcf\u6b21\u767b\u5f55\u7684\u8bb0\u5f55\uff0c\u6216\u8005\u60a8\u53ef\u80fd\u5e0c\u671b\u8ddf\u8e2a\u7279\u5b9a API \u65b9\u6cd5\u88ab\u8c03\u7528\u7684\u6b21\u6570\u3002\u65e5\u5fd7\u8bb0\u5f55\u662f\u4e00\u79cd\u8bb0\u5f55\u5e94\u7528\u7a0b\u5e8f\u884c\u4e3a\u7684\u7b80\u5355\u65b9\u6cd5\uff0c\u6bcf\u6b21\u53d1\u751f\u6709\u8da3\u7684\u4e8b\u4ef6\u65f6\uff0c\u90fd\u4f1a\u5411\u65e5\u5fd7\u5199\u5165\u4e00\u6761\u6d88\u606f\u3002<\/p>\n<p>I find the second reason for logging to be the most common. When an app is working perfectly, logs often go completely untouched. It\u2019s when there\u2019s a problem and a customer comes calling that logs become invaluable. A good set of logs can help you understand the conditions in your app that caused an error, including the context of the error itself, but also the context in previous requests.<br \/>\n\u6211\u53d1\u73b0\u65e5\u5fd7\u8bb0\u5f55\u7684\u7b2c\u4e8c\u4e2a\u539f\u56e0\u662f\u6700\u5e38\u89c1\u7684\u3002\u5f53\u5e94\u7528\u7a0b\u5e8f\u5b8c\u7f8e\u8fd0\u884c\u65f6\uff0c\u65e5\u5fd7\u901a\u5e38\u5b8c\u5168\u4fdd\u6301\u4e0d\u53d8\u3002\u5f53\u51fa\u73b0\u95ee\u9898\u5e76\u4e14\u5ba2\u6237\u6253\u7535\u8bdd\u65f6\uff0c\u65e5\u5fd7\u5c31\u4f1a\u53d8\u5f97\u975e\u5e38\u5b9d\u8d35\u3002\u4e00\u7ec4\u597d\u7684\u65e5\u5fd7\u53ef\u4ee5\u5e2e\u52a9\u60a8\u4e86\u89e3\u5e94\u7528\u4e2d\u5bfc\u81f4\u9519\u8bef\u7684\u6761\u4ef6\uff0c\u5305\u62ec\u9519\u8bef\u672c\u8eab\u7684\u4e0a\u4e0b\u6587\uff0c\u4ee5\u53ca\u4e4b\u524d\u8bf7\u6c42\u4e2d\u7684\u4e0a\u4e0b\u6587\u3002<\/p>\n<p><b>TIP<\/b> Even with extensive logging in place, you may not realize you have a problem in your app unless you look through your logs regularly. For any medium-size to large app, this becomes impractical, so monitoring services such as Sentry (<a href=\"https:\/\/sentry.io\">https:\/\/sentry.io<\/a>) can be invaluable for notifying you of problems quickly.<br \/>\n\u63d0\u793a:\u5373\u4f7f\u6709\u5927\u91cf\u7684\u65e5\u5fd7\u8bb0\u5f55\uff0c\u9664\u975e\u60a8\u5b9a\u671f\u67e5\u770b\u65e5\u5fd7\uff0c\u5426\u5219\u60a8\u4e5f\u53ef\u80fd\u4e0d\u4f1a\u610f\u8bc6\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u5b58\u5728\u95ee\u9898\u3002\u5bf9\u4e8e\u4efb\u4f55\u5927\u4e2d\u578b\u5e94\u7528\u7a0b\u5e8f\uff0c\u8fd9\u90fd\u53d8\u5f97\u4e0d\u5207\u5b9e\u9645\uff0c\u56e0\u6b64 Sentry \uff08<a href=\"https:\/\/sentry.io\">https:\/\/sentry.io<\/a>\uff09 \u7b49\u76d1\u63a7\u670d\u52a1\u5bf9\u4e8e\u5feb\u901f\u901a\u77e5\u60a8\u95ee\u9898\u975e\u5e38\u5b9d\u8d35\u3002<\/p>\n<p>If this sounds like a lot of work, you\u2019re in luck. ASP.NET Core does a ton of the \u201cbreadcrumb logging\u201d for you so that you can focus on creating high-quality log messages that provide the most value when diagnosing problems.<br \/>\n\u5982\u679c\u8fd9\u542c\u8d77\u6765\u50cf\u662f\u5f88\u591a\u5de5\u4f5c\uff0c\u90a3\u4e48\u60a8\u5f88\u5e78\u8fd0\u3002ASP.NET Core \u4e3a\u60a8\u6267\u884c\u4e86\u5927\u91cf\u7684\u201c\u75d5\u8ff9\u5bfc\u822a\u65e5\u5fd7\u8bb0\u5f55\u201d\uff0c\u4ee5\u4fbf\u60a8\u53ef\u4ee5\u4e13\u6ce8\u4e8e\u521b\u5efa\u9ad8\u8d28\u91cf\u7684\u65e5\u5fd7\u6d88\u606f\uff0c\u4ece\u800c\u5728\u8bca\u65ad\u95ee\u9898\u65f6\u63d0\u4f9b\u6700\u5927\u4ef7\u503c\u3002<\/p>\n<h3>26.1.1 Highlighting problems using custom log messages<\/h3>\n<p>26.1.1 \u4f7f\u7528\u81ea\u5b9a\u4e49\u65e5\u5fd7\u6d88\u606f\u9ad8\u4eae\u663e\u793a\u95ee\u9898<\/p>\n<p>ASP.NET Core uses logging throughout its libraries. Depending on how you configure your app, you\u2019ll have access to the details of each request and EF Core query, even without adding logging messages to your own code. In figure 26.1 you can see the log messages created when you view a single recipe in the recipe application.<br \/>\nASP.NET Core \u5728\u5176\u6574\u4e2a\u5e93\u4e2d\u4f7f\u7528\u65e5\u5fd7\u8bb0\u5f55\u3002\u6839\u636e\u4f60\u7684\u5e94\u7528\u914d\u7f6e\u65b9\u5f0f\uff0c\u4f60\u5c06\u6709\u6743\u8bbf\u95ee\u6bcf\u4e2a\u8bf7\u6c42\u548c EF Core \u67e5\u8be2\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u5373\u4f7f\u4e0d\u5411\u4f60\u81ea\u5df1\u7684\u4ee3\u7801\u6dfb\u52a0\u65e5\u5fd7\u8bb0\u5f55\u6d88\u606f\u4e5f\u662f\u5982\u6b64\u3002\u5728\u56fe 26.1 \u4e2d\uff0c\u60a8\u53ef\u4ee5\u770b\u5230\u5728\u914d\u65b9\u5e94\u7528\u7a0b\u5e8f\u4e2d\u67e5\u770b\u5355\u4e2a\u914d\u65b9\u65f6\u521b\u5efa\u7684\u65e5\u5fd7\u6d88\u606f\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2601.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 26.1 The ASP.NET Core Framework libraries use logging throughout. A single request generates multiple log messages that describe the flow of the request through your application.<br \/>\n\u56fe 26.1 ASP.NET Core Framework \u5e93\u5168\u7a0b\u4f7f\u7528\u65e5\u5fd7\u8bb0\u5f55\u3002\u5355\u4e2a\u8bf7\u6c42\u4f1a\u751f\u6210\u591a\u6761\u65e5\u5fd7\u6d88\u606f\uff0c\u7528\u4e8e\u63cf\u8ff0\u8bf7\u6c42\u901a\u8fc7\u5e94\u7528\u7a0b\u5e8f\u7684\u6d41\u5411\u3002<\/p>\n<p>This gives you a lot of useful information. You can see which URL was requested, the Razor Page and page handler that were invoked (for a Razor Pages app), the Entity Framework Core (EF Core )database command, the action result executed, and the response. This information can be invaluable when you\u2019re trying to isolate a problem, whether it\u2019s a bug in a production app or a feature in development when you\u2019re working locally.<br \/>\n\u8fd9\u4e3a\u60a8\u63d0\u4f9b\u4e86\u5f88\u591a\u6709\u7528\u7684\u4fe1\u606f\u3002\u60a8\u53ef\u4ee5\u67e5\u770b\u8bf7\u6c42\u7684 URL\u3001\u8c03\u7528\u7684 Razor Page \u548c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff08\u9488\u5bf9 Razor Pages \u5e94\u7528\uff09\u3001Entity Framework Core \uff08EF Core\uff09 \u6570\u636e\u5e93\u547d\u4ee4\u3001\u6267\u884c\u7684\u4f5c\u7ed3\u679c\u548c\u54cd\u5e94\u3002\u5f53\u60a8\u5c1d\u8bd5\u9694\u79bb\u95ee\u9898\u65f6\uff0c\u65e0\u8bba\u662f\u751f\u4ea7\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u9519\u8bef\u8fd8\u662f\u672c\u5730\u5de5\u4f5c\u65f6\u5f00\u53d1\u4e2d\u7684\u529f\u80fd\uff0c\u8fd9\u4e9b\u4fe1\u606f\u90fd\u975e\u5e38\u5b9d\u8d35\u3002<\/p>\n<p>This infrastructure logging can be useful, but log messages that you create yourself can have even greater value. For example, you may be able to spot the cause of the error from the log messages in figure 26.1; we\u2019re attempting to view a recipe with an unknown RecipeId of 5, but it\u2019s far from obvious. If you explicitly add a log message to your app when this happens, as in figure 26.2, the problem is much more apparent.<br \/>\n\u6b64\u57fa\u7840\u7ed3\u6784\u65e5\u5fd7\u8bb0\u5f55\u53ef\u80fd\u5f88\u6709\u7528\uff0c\u4f46\u60a8\u81ea\u5df1\u521b\u5efa\u7684\u65e5\u5fd7\u6d88\u606f\u53ef\u80fd\u5177\u6709\u66f4\u5927\u7684\u4ef7\u503c\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u80fd\u80fd\u591f\u4ece\u56fe 26.1 \u4e2d\u7684\u65e5\u5fd7\u6d88\u606f\u4e2d\u53d1\u73b0\u9519\u8bef\u7684\u539f\u56e0;\u6211\u4eec\u6b63\u5728\u5c1d\u8bd5\u67e5\u770b RecipeId \u672a\u77e5\u4e3a 5 \u7684\u914d\u65b9\uff0c\u4f46\u8fd9\u8fdc\u975e\u663e\u800c\u6613\u89c1\u3002\u5982\u679c\u4f60\u5728\u53d1\u751f\u8fd9\u79cd\u60c5\u51b5\u65f6\u663e\u5f0f\u5730\u5411\u4f60\u7684\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u4e00\u6761\u65e5\u5fd7\u6d88\u606f\uff0c\u5982\u56fe 26.2 \u6240\u793a\uff0c\u95ee\u9898\u4f1a\u66f4\u52a0\u660e\u663e\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2602.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 26.2 You can write your own logs. These are often more useful for identifying problems and interesting events in your apps.<br \/>\n\u56fe 26.2 \u60a8\u53ef\u4ee5\u7f16\u5199\u81ea\u5df1\u7684\u65e5\u5fd7\u3002\u8fd9\u4e9b\u901a\u5e38\u5bf9\u4e8e\u8bc6\u522b\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u95ee\u9898\u548c\u6709\u8da3\u7684\u4e8b\u4ef6\u66f4\u6709\u7528\u3002<\/p>\n<p>This custom log message easily stands out and clearly states both the problem (the recipe with the requested ID doesn\u2019t exist) and the parameters\/variables that led to it (the ID value of 5). Adding similar log messages to your own applications will make it easier for you to diagnose problems, track important events, and generally know what your app is doing.<br \/>\n\u6b64\u81ea\u5b9a\u4e49\u65e5\u5fd7\u6d88\u606f\u5f88\u5bb9\u6613\u8131\u9896\u800c\u51fa\uff0c\u5e76\u6e05\u695a\u5730\u8bf4\u660e\u4e86\u95ee\u9898\uff08\u5177\u6709\u8bf7\u6c42 ID \u7684\u914d\u65b9\u4e0d\u5b58\u5728\uff09\u548c\u5bfc\u81f4\u95ee\u9898\u7684\u53c2\u6570\/\u53d8\u91cf\uff08ID \u503c\u4e3a 5\uff09\u3002\u5c06\u7c7b\u4f3c\u7684\u65e5\u5fd7\u6d88\u606f\u6dfb\u52a0\u5230\u60a8\u81ea\u5df1\u7684\u5e94\u7528\u7a0b\u5e8f\u5c06\u4f7f\u60a8\u66f4\u5bb9\u6613\u8bca\u65ad\u95ee\u9898\u3001\u8ddf\u8e2a\u91cd\u8981\u4e8b\u4ef6\uff0c\u5e76\u4e14\u901a\u5e38\u53ef\u4ee5\u4e86\u89e3\u5e94\u7528\u7a0b\u5e8f\u6b63\u5728\u505a\u4ec0\u4e48\u3002<\/p>\n<p>I hope you\u2019re now motivated to add logging to your apps, so we\u2019ll dig into the details of what that involves. In section 26.1.2 you\u2019ll see how to create a log message and how to define where the log messages are written. We\u2019ll look in detail at these two aspects in sections 26.2 and 26.3; first, though, we\u2019ll look at where they fit in terms of the ASP.NET Core logging framework as a whole.<br \/>\n\u6211\u5e0c\u671b\u60a8\u73b0\u5728\u6709\u52a8\u529b\u5c06\u65e5\u5fd7\u8bb0\u5f55\u6dfb\u52a0\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\uff0c\u56e0\u6b64\u6211\u4eec\u5c06\u6df1\u5165\u7814\u7a76\u5176\u4e2d\u6d89\u53ca\u7684\u7ec6\u8282\u3002\u5728 Section 26.1.2 \u4e2d\uff0c\u60a8\u5c06\u770b\u5230\u5982\u4f55\u521b\u5efa\u65e5\u5fd7\u6d88\u606f\u4ee5\u53ca\u5982\u4f55\u5b9a\u4e49\u65e5\u5fd7\u6d88\u606f\u7684\u5199\u5165\u4f4d\u7f6e\u3002\u6211\u4eec\u5c06\u5728 26.2 \u548c 26.3 \u8282\u4e2d\u8be6\u7ec6\u4ecb\u7ecd\u8fd9\u4e24\u4e2a\u65b9\u9762;\u4e0d\u8fc7\uff0c\u9996\u5148\uff0c\u6211\u4eec\u5c06\u770b\u770b\u5b83\u4eec\u5728\u6574\u4e2a ASP.NET Core \u65e5\u5fd7\u8bb0\u5f55\u6846\u67b6\u4e2d\u7684\u4f4d\u7f6e\u3002<\/p>\n<h3>26.1.2 The ASP.NET Core logging abstractions<\/h3>\n<p>26.1.2 ASP.NET Core \u65e5\u5fd7\u8bb0\u5f55\u62bd\u8c61<\/p>\n<p>The ASP.NET Core logging framework consists of several abstractions (interfaces, implementations, and helper classes), the most important of which are shown in figure 26.3:<br \/>\nASP.NET Core \u65e5\u5fd7\u8bb0\u5f55\u6846\u67b6\u7531\u51e0\u4e2a\u62bd\u8c61\uff08\u63a5\u53e3\u3001\u5b9e\u73b0\u548c\u5e2e\u52a9\u7a0b\u5e8f\u7c7b\uff09\u7ec4\u6210\uff0c\u5176\u4e2d\u6700\u91cd\u8981\u7684\u5982\u56fe 26.3 \u6240\u793a\uff1a<\/p>\n<p>\u2022  ILogger\u2014This is the interface you\u2019ll interact with in your code. It has a Log() method, which is used to write a log message.<br \/>\nILogger - \u8fd9\u662f\u60a8\u5c06\u5728\u4ee3\u7801\u4e2d\u4e0e\u4e4b\u4ea4\u4e92\u7684\u754c\u9762\u3002\u5b83\u6709\u4e00\u4e2a Log\uff08\uff09 \u65b9\u6cd5\uff0c\u7528\u4e8e\u7f16\u5199\u65e5\u5fd7\u6d88\u606f\u3002<\/p>\n<p>\u2022  ILoggerProvider\u2014This is used to create a custom instance of an ILogger, depending on the provider. A console ILoggerProvider would create an ILogger that writes to the console, whereas a file ILoggerProvider would create an ILogger that writes to a file.<br \/>\nILoggerProvider - \u7528\u4e8e\u521b\u5efa ILogger \u7684\u81ea\u5b9a\u4e49\u5b9e\u4f8b\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u63d0\u4f9b\u7a0b\u5e8f\u3002\u63a7\u5236\u53f0 ILoggerProvider \u5c06\u521b\u5efa\u5199\u5165\u63a7\u5236\u53f0\u7684 ILogger\uff0c\u800c\u6587\u4ef6 ILoggerProvider \u5c06\u521b\u5efa\u5199\u5165\u6587\u4ef6\u7684 ILogger\u3002<\/p>\n<p>\u2022  ILoggerFactory\u2014This is the glue between the ILoggerProvider instances and the ILogger you use in your code. You register ILoggerProvider instances with an ILoggerFactory and call CreateLogger() on the ILoggerFactory when you need an ILogger. The factory creates an ILogger that wraps each of the providers, so when you call the Log() method, the log is written to every provider.<br \/>\nILoggerFactory - \u8fd9\u662f ILoggerProvider \u5b9e\u4f8b\u548c\u60a8\u5728\u4ee3\u7801\u4e2d\u4f7f\u7528\u7684 ILogger \u4e4b\u95f4\u7684\u7c98\u9644\u3002\u4f7f\u7528 ILoggerFactory \u6ce8\u518c ILoggerProvider \u5b9e\u4f8b\uff0c\u5e76\u5728\u9700\u8981 ILogger \u65f6\u5bf9 ILoggerFactory \u8c03\u7528 CreateLogger \uff08\uff09 \u3002\u5de5\u5382\u4f1a\u521b\u5efa\u4e00\u4e2a ILogger \u6765\u5305\u88c5\u6bcf\u4e2a\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u56e0\u6b64\u5f53\u60a8\u8c03\u7528 Log\uff08\uff09 \u65b9\u6cd5\u65f6\uff0c\u65e5\u5fd7\u5c06\u5199\u5165\u6bcf\u4e2a\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2603.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 26.3 The components of the ASP.NET Core logging framework. You register logging providers with an ILoggerFactory, which creates implementations of ILogger. You write logs to the ILogger, which delegates to the ILogger implementations that write logs to the console or a file. You can send logs to multiple locations with this design without having to configure the locations when you create a log message.<br \/>\n\u56fe 26.3 ASP.NET Core \u65e5\u5fd7\u8bb0\u5f55\u6846\u67b6\u7684\u7ec4\u4ef6\u3002\u5411 ILoggerFactory \u6ce8\u518c\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u8fd9\u5c06\u521b\u5efa ILogger \u7684\u5b9e\u73b0\u3002\u5c06\u65e5\u5fd7\u5199\u5165 ILogger\uff0cILogger \u5c06\u59d4\u6258\u7ed9\u5c06\u65e5\u5fd7\u5199\u5165\u63a7\u5236\u53f0\u6216\u6587\u4ef6\u7684 ILogger \u5b9e\u73b0\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528\u6b64\u8bbe\u8ba1\u5c06\u65e5\u5fd7\u53d1\u9001\u5230\u591a\u4e2a\u4f4d\u7f6e\uff0c\u800c\u65e0\u9700\u5728\u521b\u5efa\u65e5\u5fd7\u6d88\u606f\u65f6\u914d\u7f6e\u4f4d\u7f6e\u3002<\/p>\n<p>The design in figure 26.3 makes it easy to add or change where your application writes the log messages without having to change your application code. The following listing shows all the code required to add an ILoggerProvider that writes logs to the console.<br \/>\n\u56fe 26.3 \u4e2d\u7684\u8bbe\u8ba1\u4f7f\u6dfb\u52a0\u6216\u66f4\u6539\u5e94\u7528\u7a0b\u5e8f\u5199\u5165\u65e5\u5fd7\u6d88\u606f\u7684\u4f4d\u7f6e\u53d8\u5f97\u5bb9\u6613\uff0c\u800c\u65e0\u9700\u66f4\u6539\u5e94\u7528\u7a0b\u5e8f\u4ee3\u7801\u3002\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86\u6dfb\u52a0\u5c06\u65e5\u5fd7\u5199\u5165\u63a7\u5236\u53f0\u7684 ILoggerProvider \u6240\u9700\u7684\u6240\u6709\u4ee3\u7801\u3002<\/p>\n<p>Listing 26.1 Adding a console log provider in Program.cs<br \/>\n\u6e05\u5355 26.1 \u5728 Program.cs \u4e2d\u6dfb\u52a0\u63a7\u5236\u53f0\u65e5\u5fd7\u63d0\u4f9b\u7a0b\u5e8f<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\nbuilder.Logging.AddConsole() \u2776\n\nWebApplication app = builder.Build();\n\napp.MapGet(&quot;\/&quot;, () =&gt; &quot;Hello World!&quot;);\n\napp.Run();<\/code><\/pre>\n<p>\u2776 Adds a new provider using the Logging property on WebApplicationBuilder<br \/>\n\u4f7f\u7528 WebApplicationBuilder \u4e0a\u7684 Logging \u5c5e\u6027\u6dfb\u52a0\u65b0\u7684\u63d0\u4f9b\u7a0b\u5e8f<\/p>\n<p><b>NOTE<\/b> The console logger is added by default by WebApplicationBuilder, as you\u2019ll see in section 26.3.<br \/>\n\u6ce8\u610f:\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u63a7\u5236\u53f0 Logger \u7531 WebApplicationBuilder \u6dfb\u52a0\uff0c\u5982\u7b2c 26.3 \u8282\u6240\u793a\u3002<\/p>\n<p>Other than this configuration on WebApplicationBuilder, you don\u2019t interact with ILoggerProvider instances directly. Instead, you write logs using an instance of ILogger, as you\u2019ll see in the next section.<br \/>\n\u9664\u4e86 WebApplicationBuilder \u4e0a\u7684\u6b64\u914d\u7f6e\u4e4b\u5916\uff0c\u60a8\u4e0d\u76f4\u63a5\u4e0e ILoggerProvider \u5b9e\u4f8b\u4ea4\u4e92\u3002\u76f8\u53cd\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 ILogger \u7684\u5b9e\u4f8b\u7f16\u5199\u65e5\u5fd7\uff0c\u5982\u4e0b\u4e00\u8282\u6240\u793a\u3002<\/p>\n<h2>26.2 Adding log messages to your application<\/h2>\n<p>26.2 \u5411\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u65e5\u5fd7\u6d88\u606f<\/p>\n<p>In this section we\u2019ll look in detail at how to create log messages in your own application. You\u2019ll learn how to create an instance of ILogger, and how to use it to add logging to an existing application. Finally, we\u2019ll look at the properties that make up a logging record, what they mean, and what you can use them for.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u8be6\u7ec6\u4ecb\u7ecd\u5982\u4f55\u5728\u60a8\u81ea\u5df1\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u521b\u5efa\u65e5\u5fd7\u6d88\u606f\u3002\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u521b\u5efa ILogger \u7684\u5b9e\u4f8b\uff0c\u4ee5\u53ca\u5982\u4f55\u4f7f\u7528\u5b83\u6765\u5411\u73b0\u6709\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u65e5\u5fd7\u8bb0\u5f55\u3002\u6700\u540e\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u6784\u6210\u65e5\u5fd7\u8bb0\u5f55\u7684\u5c5e\u6027\u3001\u5b83\u4eec\u7684\u542b\u4e49\u4ee5\u53ca\u60a8\u53ef\u4ee5\u4f7f\u7528\u5b83\u4eec\u7684\u7528\u9014\u3002<\/p>\n<p>Logging, like almost everything in ASP.NET Core, is available through DI. To add logging to your own services, you need only inject an instance of <code>ILogger&lt;T&gt;<\/code>, where T is the type of your service.<br \/>\n\u4e0e ASP.NET Core \u4e2d\u7684\u51e0\u4e4e\u6240\u6709\u5185\u5bb9\u4e00\u6837\uff0c\u65e5\u5fd7\u8bb0\u5f55\u53ef\u901a\u8fc7 DI \u83b7\u5f97\u3002\u8981\u5c06\u65e5\u5fd7\u8bb0\u5f55\u6dfb\u52a0\u5230\u60a8\u81ea\u5df1\u7684\u670d\u52a1\u4e2d\uff0c\u60a8\u53ea\u9700\u6ce8\u5165<code>ILogger&lt;T&gt;<\/code>\u7684\u5b9e\u4f8b\uff0c\u5176\u4e2d T \u662f\u60a8\u7684\u670d\u52a1\u7c7b\u578b\u3002<\/p>\n<p><b>NOTE<\/b>  When you inject <code>ILogger&lt;T&gt;<\/code>, the DI container indirectly calls ILoggerFactory.CreateLogger<T>() to create the wrapped ILogger of figure 26.3. In section 26.2.2 you\u2019ll see how to work directly with ILoggerFactory if you prefer. The <code>ILogger&lt;T&gt;<\/code> interface also implements the nongeneric ILogger interface but includes additional convenience methods.<br \/>\n\u6ce8\u610f\u5f53\u60a8\u6ce8\u5165 <code>ILogger&lt;T&gt;<\/code> \u65f6\uff0cDI \u5bb9\u5668\u4f1a\u95f4\u63a5\u8c03\u7528 ILoggerFactory.CreateLogger\uff08\uff09 \u6765\u521b\u5efa\u56fe 26.3 \u4e2d\u5305\u88c5\u7684 ILogger\u3002\u5728\u7b2c 26.2.2 \u8282\u4e2d\uff0c\u5982\u679c\u60a8\u613f\u610f\uff0c\u60a8\u5c06\u770b\u5230\u5982\u4f55\u76f4\u63a5\u4f7f\u7528 ILoggerFactory\u3002<code>ILogger&lt;T&gt;<\/code>\u63a5\u53e3\u8fd8\u5b9e\u73b0\u975e\u6cdb\u578b ILogger \u63a5\u53e3\uff0c\u4f46\u5305\u542b\u5176\u4ed6\u4fbf\u6377\u65b9\u6cd5\u3002<\/p>\n<p>You can use the injected ILogger instance to create log messages, which it writes to each configured ILoggerProvider. The following listing shows how to inject an <code>ILogger&lt;&gt;<\/code> instance into the PageModel of the Index.cshtml Razor Page for the recipe application from previous chapters and how to write a log message indicating how many recipes were found.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u6ce8\u5165\u7684 ILogger \u5b9e\u4f8b\u521b\u5efa\u65e5\u5fd7\u6d88\u606f\uff0c\u5e76\u5c06\u5176\u5199\u5165\u6bcf\u4e2a\u914d\u7f6e\u7684 ILoggerProvider\u3002\u4ee5\u4e0b\u5217\u8868\u663e\u793a\u4e86\u5982\u4f55\u5c06 <code>ILogger&lt;&gt;<\/code> \u5b9e\u4f8b\u6ce8\u5165\u524d\u9762\u7ae0\u8282\u4e2d\u914d\u65b9\u5e94\u7528\u7a0b\u5e8f\u7684 Index.cshtml Razor Page \u7684 PageModel\uff0c\u4ee5\u53ca\u5982\u4f55\u7f16\u5199\u6307\u793a\u627e\u5230\u7684\u914d\u65b9\u6570\u7684\u65e5\u5fd7\u6d88\u606f\u3002<\/p>\n<p>Listing 26.2 Injecting ILogger into a class and writing a log message<br \/>\n\u6e05\u5355 26.2 \u5c06 ILogger \u6ce8\u5165\u5230\u7c7b\u4e2d\u5e76\u7f16\u5199\u65e5\u5fd7\u6d88\u606f<\/p>\n<pre><code>public class IndexModel : PageModel\n{\n    private readonly RecipeService _service;\n    private readonly ILogger&lt;IndexModel&gt; _log;      #A\n\n    public ICollection&lt;RecipeSummaryViewModel&gt; Recipes { get; set; }\n\n    public IndexModel(\n        RecipeService service,\n        ILogger&lt;IndexModel&gt; log)                   #A\n    {\n        _service = service;\n        _log = log;                                #A\n    }\n\n    public void OnGet()\n    {\n        Recipes = _service.GetRecipes();\n        _log.LogInformation(                                  #B\n            &quot;Loaded {RecipeCount} recipes&quot;, Recipes.Count);   #B\n    }\n}<\/code><\/pre>\n<p>\u2776 Injects the generic ILogger<T> using DI, which implements ILogger<br \/>\n\u4f7f\u7528 DI \u6ce8\u5165\u6cdb\u578b ILogger\uff0c\u5b83\u5b9e\u73b0 ILogger<\/p>\n<p>\u2777 Writes an Information-level log. The RecipeCount variable is substituted in the message.<br \/>\n\u5199\u5165\u4fe1\u606f\u7ea7\u65e5\u5fd7\u3002RecipeCount \u53d8\u91cf\u5728\u6d88\u606f\u4e2d\u88ab\u66ff\u6362\u3002<\/p>\n<p>In this example you\u2019re using one of the many extension methods on ILogger to create the log message, LogInformation(). There are many extension methods on ILogger that let you easily specify a LogLevel for the message.<br \/>\n\u5728\u6b64\u793a\u4f8b\u4e2d\uff0c\u60a8\u5c06\u4f7f\u7528 ILogger \u4e0a\u7684\u4f17\u591a\u6269\u5c55\u65b9\u6cd5\u4e4b\u4e00\u6765\u521b\u5efa\u65e5\u5fd7\u6d88\u606f LogInformation\uff08\uff09\u3002ILogger \u4e0a\u6709\u8bb8\u591a\u6269\u5c55\u65b9\u6cd5\uff0c\u53ef\u8ba9\u60a8\u8f7b\u677e\u6307\u5b9a\u6d88\u606f\u7684 LogLevel\u3002<\/p>\n<p><b>DEFINITION<\/b> The log level of a log is how important it is and is defined by the LogLevel enum. Every log message has a log level.<br \/>\n\u5b9a\u4e49:\u65e5\u5fd7\u7684\u65e5\u5fd7\u7ea7\u522b\u662f\u5b83\u7684\u91cd\u8981\u6027\uff0c\u7531 LogLevel \u679a\u4e3e\u5b9a\u4e49\u3002\u6bcf\u6761\u65e5\u5fd7\u6d88\u606f\u90fd\u6709\u4e00\u4e2a\u65e5\u5fd7\u7ea7\u522b\u3002<\/p>\n<p>You can also see that the message you pass to the LogInformation method has a placeholder indicated by braces, {RecipeCount}, and you pass an additional parameter, Recipes.Count, to the logger. The logger replaces the placeholder with the parameter at runtime. Placeholders are matched with parameters by position, so if you include two placeholders, for example, the second placeholder is matched with the second parameter.<br \/>\n\u60a8\u8fd8\u53ef\u4ee5\u770b\u5230\uff0c\u4f20\u9012\u7ed9 LogInformation \u65b9\u6cd5\u7684\u6d88\u606f\u5177\u6709\u7531\u5927\u62ec\u53f7\u6307\u793a\u7684\u5360\u4f4d\u7b26 {RecipeCount}\uff0c\u5e76\u4e14\u60a8\u5c06\u9644\u52a0\u53c2\u6570 Recipes.Count \u4f20\u9012\u7ed9\u8bb0\u5f55\u5668\u3002\u8bb0\u5f55\u5668\u5728\u8fd0\u884c\u65f6\u5c06\u5360\u4f4d\u7b26\u66ff\u6362\u4e3a\u53c2\u6570\u3002\u5360\u4f4d\u7b26\u6309\u4f4d\u7f6e\u4e0e\u53c2\u6570\u5339\u914d\uff0c\u56e0\u6b64\uff0c\u4f8b\u5982\uff0c\u5982\u679c\u60a8\u5305\u62ec\u4e24\u4e2a\u5360\u4f4d\u7b26\uff0c\u5219\u7b2c\u4e8c\u4e2a\u5360\u4f4d\u7b26\u5c06\u4e0e\u7b2c\u4e8c\u4e2a\u53c2\u6570\u5339\u914d\u3002<\/p>\n<p><b>TIP<\/b> You could have used normal string interpolation to create the log message, as in $&quot;Loaded {Recipes.Count} recipes&quot;. But I recommend always using placeholders, as they provide additional information for the logger that can be used for structured logging, as you\u2019ll see in section 26.5.<br \/>\n\u63d0\u793a:\u60a8\u53ef\u4ee5\u4f7f\u7528\u666e\u901a\u5b57\u7b26\u4e32\u63d2\u503c\u6765\u521b\u5efa\u65e5\u5fd7\u6d88\u606f\uff0c\u5982 $\u201cLoaded {Recipes.Count} recipes\u201d\u3002\u4f46\u662f\u6211\u5efa\u8bae\u59cb\u7ec8\u4f7f\u7528\u5360\u4f4d\u7b26\uff0c\u56e0\u4e3a\u5b83\u4eec\u4e3a Logger \u63d0\u4f9b\u4e86\u53ef\u7528\u4e8e\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u7684\u9644\u52a0\u4fe1\u606f\uff0c\u5982\u60a8\u5c06\u5728Section 26.5\u4e2d\u770b\u5230\u7684\u90a3\u6837\u3002<\/p>\n<p>When the OnGet page handler in the IndexModel executes, ILogger writes a message to any configured logging providers. The exact format of the log message varies from provider to provider, but figure 26.4 shows how the console provider displays the log message from listing 26.2.<br \/>\n\u5f53 IndexModel \u4e2d\u7684 OnGet \u9875\u9762\u5904\u7406\u7a0b\u5e8f\u6267\u884c\u65f6\uff0c ILogger \u4f1a\u5c06\u6d88\u606f\u5199\u5165\u4efb\u4f55\u5df2\u914d\u7f6e\u7684\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u3002\u65e5\u5fd7\u6d88\u606f\u7684\u786e\u5207\u683c\u5f0f\u56e0\u63d0\u4f9b\u8005\u800c\u5f02\uff0c\u4f46\u56fe 26.4 \u663e\u793a\u4e86\u63a7\u5236\u53f0\u63d0\u4f9b\u8005\u5982\u4f55\u663e\u793a\u6e05\u5355 26.2 \u4e2d\u7684\u65e5\u5fd7\u6d88\u606f\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2604.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 26.4 An example log message as it\u2019s written to the default console provider. The log-level category provides information about how important the message is and where it was generated. The EventId provides a way to identify similar log messages.<br \/>\n\u56fe 26.4 \u5199\u5165\u9ed8\u8ba4\u63a7\u5236\u53f0\u63d0\u4f9b\u7a0b\u5e8f\u65f6\u7684\u65e5\u5fd7\u6d88\u606f\u793a\u4f8b\u3002\u65e5\u5fd7\u7ea7\u522b\u7c7b\u522b\u63d0\u4f9b\u6709\u5173\u6d88\u606f\u7684\u91cd\u8981\u6027\u4ee5\u53ca\u6d88\u606f\u751f\u6210\u4f4d\u7f6e\u7684\u4fe1\u606f\u3002EventId \u63d0\u4f9b\u4e86\u4e00\u79cd\u8bc6\u522b\u7c7b\u4f3c\u65e5\u5fd7\u6d88\u606f\u7684\u65b9\u6cd5\u3002<\/p>\n<p>The exact presentation of the message will vary depending on where the log is written, but each log record includes up to six common elements:<br \/>\n\u6d88\u606f\u7684\u786e\u5207\u8868\u793a\u65b9\u5f0f\u4f1a\u56e0\u65e5\u5fd7\u7684\u5199\u5165\u4f4d\u7f6e\u800c\u5f02\uff0c\u4f46\u6bcf\u6761\u65e5\u5fd7\u8bb0\u5f55\u6700\u591a\u5305\u542b\u516d\u4e2a\u5e38\u89c1\u5143\u7d20\uff1a<\/p>\n<p>\u2022  Log level\u2014The log level of the log is how important it is and is defined by the LogLevel enum.<br \/>\n\u65e5\u5fd7\u7ea7\u522b - \u65e5\u5fd7\u7684\u65e5\u5fd7\u7ea7\u522b\u662f\u5b83\u7684\u91cd\u8981\u6027\uff0c\u7531 LogLevel \u679a\u4e3e\u5b9a\u4e49\u3002<\/p>\n<p>\u2022  Event category\u2014The category may be any string value, but it\u2019s typically set to the name of the class creating the log. For <code>ILogger&lt;T&gt;<\/code>, the full name of the type T is the category.<br \/>\n\u4e8b\u4ef6\u7c7b\u522b - \u7c7b\u522b\u53ef\u4ee5\u662f\u4efb\u4f55\u5b57\u7b26\u4e32\u503c\uff0c\u4f46\u901a\u5e38\u8bbe\u7f6e\u4e3a\u521b\u5efa\u65e5\u5fd7\u7684\u7c7b\u7684\u540d\u79f0\u3002\u5bf9\u4e8e<code>ILogger&lt;T&gt;<\/code>\uff0c\u7c7b\u578b T \u7684\u5168\u540d\u662f\u7c7b\u522b\u3002<\/p>\n<p>\u2022  Message\u2014This is the content of the log message. It can be a static string, or it can contain placeholders for variables, as shown in listing 26.2. Placeholders are indicated by braces, {} and are replaced by the provided parameter values.<br \/>\nMessage - \u8fd9\u662f\u65e5\u5fd7\u6d88\u606f\u7684\u5185\u5bb9\u3002\u5b83\u53ef\u4ee5\u662f\u4e00\u4e2a\u9759\u6001\u5b57\u7b26\u4e32\uff0c\u4e5f\u53ef\u4ee5\u5305\u542b\u53d8\u91cf\u7684\u5360\u4f4d\u7b26\uff0c\u5982\u6e05\u5355 26.2 \u6240\u793a\u3002\u5360\u4f4d\u7b26\u7531\u5927\u62ec\u53f7 {} \u8868\u793a\uff0c\u5e76\u66ff\u6362\u4e3a\u63d0\u4f9b\u7684\u53c2\u6570\u503c\u3002<\/p>\n<p>\u2022  Parameters\u2014If the message contains placeholders, they\u2019re associated with the provided parameters. For the example in listing 26.2, the value of Recipes.Count is assigned to the placeholder called RecipeCount. Some loggers can extract these values and expose them in your logs, as you\u2019ll see in section 26.5.<br \/>\n\u53c2\u6570 - \u5982\u679c\u6d88\u606f\u5305\u542b\u5360\u4f4d\u7b26\uff0c\u5219\u5b83\u4eec\u4e0e\u63d0\u4f9b\u7684\u53c2\u6570\u76f8\u5173\u8054\u3002\u5bf9\u4e8e\u6e05\u5355 26.2 \u4e2d\u7684\u793a\u4f8b\uff0cRecipes.Count \u7684\u503c\u88ab\u5206\u914d\u7ed9\u540d\u4e3a RecipeCount \u7684\u5360\u4f4d\u7b26\u3002\u4e00\u4e9b Logger \u53ef\u4ee5\u63d0\u53d6\u8fd9\u4e9b\u503c\u5e76\u5728\u60a8\u7684\u65e5\u5fd7\u4e2d\u516c\u5f00\u5b83\u4eec\uff0c\u6b63\u5982\u60a8\u5c06\u5728Section 26.5\u4e2d\u770b\u5230\u7684\u90a3\u6837\u3002<\/p>\n<p>\u2022  Exception\u2014If an exception occurs, you can pass the exception object to the logging function along with the message and other parameters. The logger records the exception in addition to the message itself.<br \/>\nException - \u5982\u679c\u53d1\u751f\u5f02\u5e38\uff0c\u53ef\u4ee5\u5c06 exception \u5bf9\u8c61\u4e0e\u6d88\u606f\u548c\u5176\u4ed6\u53c2\u6570\u4e00\u8d77\u4f20\u9012\u7ed9\u65e5\u5fd7\u8bb0\u5f55\u51fd\u6570\u3002\u9664\u4e86\u6d88\u606f\u672c\u8eab\u4e4b\u5916\uff0cLogger \u8fd8\u4f1a\u8bb0\u5f55\u5f02\u5e38\u3002<\/p>\n<p>\u2022  EventId\u2014This is an optional integer identifier for the error, which can be used to quickly find all similar logs in a series of log messages. You might use an EventId of 1000 when a user attempts to load a non-existent recipe and an EventId of 1001 when a user attempts to access a recipe they don\u2019t have permission to access. If you don\u2019t provide an EventId, the value 0 is used.<br \/>\nEventId - \u8fd9\u662f\u9519\u8bef\u7684\u53ef\u9009\u6574\u6570\u6807\u8bc6\u7b26\uff0c\u53ef\u7528\u4e8e\u5728\u4e00\u7cfb\u5217\u65e5\u5fd7\u6d88\u606f\u4e2d\u5feb\u901f\u67e5\u627e\u6240\u6709\u76f8\u4f3c\u65e5\u5fd7\u3002\u5f53\u7528\u6237\u5c1d\u8bd5\u52a0\u8f7d\u4e0d\u5b58\u5728\u7684\u914d\u65b9\u65f6\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 EventId 1000\uff0c\u5f53\u7528\u6237\u5c1d\u8bd5\u8bbf\u95ee\u4ed6\u4eec\u65e0\u6743\u8bbf\u95ee\u7684\u914d\u65b9\u65f6\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 EventId 1001\u3002\u5982\u679c\u60a8\u672a\u63d0\u4f9b EventId\uff0c\u5219\u4f7f\u7528\u503c 0\u3002<\/p>\n<blockquote>\n<p>High-performance logging with source generators<br \/>\n\u4f7f\u7528\u6e90\u751f\u6210\u5668\u8fdb\u884c\u9ad8\u6027\u80fd\u65e5\u5fd7\u8bb0\u5f55\u6e90<\/p>\n<p>Source generators are a compiler feature introduced in C# 9. Using this feature, you can automatically generate boilerplate code when your project compiles. .NET 7 includes several built-in source generators, such as the Regex generator I described in chapter 14. There\u2019s also a source generator that works with ILogger, which can help you avoid pitfalls such as accidentally using interpolated strings, and makes more advanced and performant logging patterns easy to use.<br \/>\n\u751f\u6210\u5668\u662f C# 9 \u4e2d\u5f15\u5165\u7684\u4e00\u9879\u7f16\u8bd1\u5668\u529f\u80fd\u3002\u4f7f\u7528\u6b64\u529f\u80fd\uff0c\u60a8\u53ef\u4ee5\u5728\u9879\u76ee\u7f16\u8bd1\u65f6\u81ea\u52a8\u751f\u6210\u6837\u677f\u4ee3\u7801\u3002.NET 7 \u5305\u62ec\u51e0\u4e2a\u5185\u7f6e\u7684\u6e90\u751f\u6210\u5668\uff0c\u4f8b\u5982\u6211\u5728\u7b2c 14 \u7ae0\u4e2d\u63cf\u8ff0\u7684 Regex \u751f\u6210\u5668\u3002\u8fd8\u6709\u4e00\u4e2a\u4e0e ILogger \u914d\u5408\u4f7f\u7528\u7684\u6e90\u751f\u6210\u5668\uff0c\u5b83\u53ef\u4ee5\u5e2e\u52a9\u60a8\u907f\u514d\u8bef\u533a\uff0c\u4f8b\u5982\u610f\u5916\u4f7f\u7528\u5185\u63d2\u5b57\u7b26\u4e32\uff0c\u5e76\u4f7f\u66f4\u9ad8\u7ea7\u548c\u9ad8\u6027\u80fd\u7684\u65e5\u5fd7\u8bb0\u5f55\u6a21\u5f0f\u6613\u4e8e\u4f7f\u7528\u3002<\/p>\n<p>To use the logging source generator in the OnGet handler from listing 26.2, define a partial method in the IndexModel class, decorate it with a [LoggerMessage] attribute, and invoke the method inside the OnGet handler method:<br \/>\n\u8981\u5728\u6e05\u5355 26.2 \u4e2d\u7684 OnGet \u5904\u7406\u7a0b\u5e8f\u4e2d\u4f7f\u7528\u65e5\u5fd7\u8bb0\u5f55\u6e90\u751f\u6210\u5668\uff0c\u8bf7\u5728 IndexModel \u7c7b\u4e2d\u5b9a\u4e49\u4e00\u4e2a\u5206\u90e8\u65b9\u6cd5\uff0c\u7528 [LoggerMessage] \u5c5e\u6027\u4fee\u9970\u5b83\uff0c\u5e76\u5728 OnGet \u5904\u7406\u7a0b\u5e8f\u65b9\u6cd5\u4e2d\u8c03\u7528\u8be5\u65b9\u6cd5\uff1a<\/p>\n<\/blockquote>\n<pre><code>[LoggerMessage(10, LogLevel.Information, &quot;Loaded {RecipeCount} recipes&quot;)]\npartial void LogLoadedRecipes(int recipeCount);\n\npublic void OnGet()\n{\nRecipes = _service.GetRecipes();\nLogLoadedRecipes(Recipes.Count);\n}<\/code><\/pre>\n<blockquote>\n<p>The [LoggerMessage] attribute defines the event ID, log level, and message the log message uses, and the parameters of the partial method it decorates are substituted into the message at runtime. This pattern also comes with several analyzers to make sure you use it correctly in your code while optimizing the generated code behind the scenes to prevent allocations where possible.<br \/>\n\u8be5 [LoggerMessage] \u5c5e\u6027\u5b9a\u4e49\u65e5\u5fd7\u6d88\u606f\u4f7f\u7528\u7684\u4e8b\u4ef6 ID\u3001\u65e5\u5fd7\u7ea7\u522b\u548c\u6d88\u606f\uff0c\u5e76\u4e14\u5b83\u4fee\u9970\u7684\u5206\u90e8\u65b9\u6cd5\u7684\u53c2\u6570\u5728\u8fd0\u884c\u65f6\u66ff\u6362\u4e3a\u6d88\u606f\u3002\u6b64\u6a21\u5f0f\u8fd8\u9644\u5e26\u4e86\u591a\u4e2a\u5206\u6790\u5668\uff0c\u4ee5\u786e\u4fdd\u60a8\u5728\u4ee3\u7801\u4e2d\u6b63\u786e\u4f7f\u7528\u5b83\uff0c\u540c\u65f6\u5728\u540e\u53f0\u4f18\u5316\u751f\u6210\u7684\u4ee3\u7801\uff0c\u4ee5\u5c3d\u53ef\u80fd\u9632\u6b62\u5206\u914d\u3002<\/p>\n<p>The logging source generator is optional, so it\u2019s up to you whether to use it. You can read more about the source generator, the extra configuration options, and how it works on my blog at <a href=\"http:\/\/mng.bz\/vn14\">http:\/\/mng.bz\/vn14<\/a> and in the documentation at <a href=\"http:\/\/mng.bz\/4D1j\">http:\/\/mng.bz\/4D1j<\/a>.<br \/>\n\u65e5\u5fd7\u8bb0\u5f55\u6e90\u751f\u6210\u5668\u662f\u53ef\u9009\u7684\uff0c\u56e0\u6b64\u662f\u5426\u4f7f\u7528\u5b83\u53d6\u51b3\u4e8e\u60a8\u3002\u60a8\u53ef\u4ee5\u5728\u6211\u7684\u535a\u5ba2 <a href=\"http:\/\/mng.bz\/vn14\">http:\/\/mng.bz\/vn14<\/a> \u548c\u6587\u6863 <a href=\"http:\/\/mng.bz\/4D1j\">http:\/\/mng.bz\/4D1j<\/a> \u4e2d\u9605\u8bfb\u6709\u5173\u6e90\u751f\u6210\u5668\u3001\u989d\u5916\u914d\u7f6e\u9009\u9879\u53ca\u5176\u5de5\u4f5c\u539f\u7406\u7684\u66f4\u591a\u4fe1\u606f\u3002<\/p>\n<\/blockquote>\n<p>Not every log message will have all the possible elements. You won\u2019t always have an Exception or parameters, for example, and it\u2019s common to omit the EventId. There are various overloads to the logging methods that take these elements as additional method parameters. Besides these optional elements, each message has, at very least, a level, category, and message. These are the key features of the log, so we\u2019ll look at each in turn.<br \/>\n\u5e76\u975e\u6bcf\u6761\u65e5\u5fd7\u6d88\u606f\u90fd\u5305\u542b\u6240\u6709\u53ef\u80fd\u7684\u5143\u7d20\u3002\u4f8b\u5982\uff0c\u60a8\u4e0d\u4f1a\u603b\u662f\u6709 Exception \u6216\u53c2\u6570\uff0c\u7701\u7565 EventId \u662f\u5f88\u5e38\u89c1\u7684\u3002\u65e5\u5fd7\u8bb0\u5f55\u65b9\u6cd5\u5b58\u5728\u5404\u79cd\u91cd\u8f7d\uff0c\u8fd9\u4e9b\u91cd\u8f7d\u5c06\u8fd9\u4e9b\u5143\u7d20\u4f5c\u4e3a\u9644\u52a0\u65b9\u6cd5\u53c2\u6570\u3002\u9664\u4e86\u8fd9\u4e9b\u53ef\u9009\u5143\u7d20\u4e4b\u5916\uff0c\u6bcf\u6761\u6d88\u606f\u81f3\u5c11\u5177\u6709 level\u3001category \u548c message\u3002\u8fd9\u4e9b\u662f\u65e5\u5fd7\u7684\u4e3b\u8981\u529f\u80fd\uff0c\u56e0\u6b64\u6211\u4eec\u5c06\u4f9d\u6b21\u67e5\u770b\u6bcf\u4e2a\u529f\u80fd\u3002<\/p>\n<h3>26.2.1 Log level: How important is the log message?<\/h3>\n<p>26.2.1 \u65e5\u5fd7\u7ea7\u522b\uff1a\u65e5\u5fd7\u6d88\u606f\u6709\u591a\u91cd\u8981\uff1f<\/p>\n<p>Whenever you create a log using ILogger, you must specify the log level. This indicates how serious or important the log message is, and it\u2019s an important factor when it comes to filtering which logs are written by a provider, as well as finding the important log messages after the fact.<br \/>\n\u6bcf\u5f53\u4f7f\u7528 ILogger \u521b\u5efa\u65e5\u5fd7\u65f6\uff0c\u90fd\u5fc5\u987b\u6307\u5b9a\u65e5\u5fd7\u7ea7\u522b\u3002\u8fd9\u8868\u660e\u65e5\u5fd7\u6d88\u606f\u7684\u4e25\u91cd\u6027\u6216\u91cd\u8981\u6027\uff0c\u5728\u7b5b\u9009\u63d0\u4f9b\u5546\u5199\u5165\u7684\u65e5\u5fd7\u4ee5\u53ca\u4e8b\u540e\u67e5\u627e\u91cd\u8981\u65e5\u5fd7\u6d88\u606f\u65f6\uff0c\u8fd9\u662f\u4e00\u4e2a\u91cd\u8981\u56e0\u7d20\u3002<\/p>\n<p>You might create an Information level log when a user starts to edit a recipe. This is useful for tracing the application\u2019s flow and behavior, but it\u2019s not important, because everything is normal. But if an exception is thrown when the user attempts to save the recipe, you might create a Warning or Error level log.<br \/>\n\u5f53\u7528\u6237\u5f00\u59cb\u7f16\u8f91\u914d\u65b9\u65f6\uff0c\u60a8\u53ef\u4ee5\u521b\u5efa Information level log\uff08\u4fe1\u606f\u7ea7\u522b\u65e5\u5fd7\uff09\u3002\u8fd9\u5bf9\u4e8e\u8ddf\u8e2a\u5e94\u7528\u7a0b\u5e8f\u7684\u6d41\u548c\u884c\u4e3a\u5f88\u6709\u7528\uff0c\u4f46\u5e76\u4e0d\u91cd\u8981\uff0c\u56e0\u4e3a\u4e00\u5207\u90fd\u5f88\u6b63\u5e38\u3002\u4f46\u662f\uff0c\u5982\u679c\u5728\u7528\u6237\u5c1d\u8bd5\u4fdd\u5b58\u914d\u65b9\u65f6\u5f15\u53d1\u5f02\u5e38\uff0c\u5219\u53ef\u4ee5\u521b\u5efa Warning \uff08\u8b66\u544a\uff09 \u6216 Error \uff08\u9519\u8bef\uff09 \u7ea7\u522b\u65e5\u5fd7\u3002<\/p>\n<p>The log level is typically set by using one of several extension methods on the ILogger interface, as shown in listing 26.3. This example creates an Information level log when the View method executes and a Warning level error if the requested recipe isn\u2019t found.<br \/>\n\u65e5\u5fd7\u7ea7\u522b\u901a\u5e38\u662f\u901a\u8fc7\u4f7f\u7528 ILogger \u63a5\u53e3\u4e0a\u7684\u51e0\u79cd\u6269\u5c55\u65b9\u6cd5\u4e4b\u4e00\u6765\u8bbe\u7f6e\u7684\uff0c\u5982\u6e05\u5355 26.3 \u6240\u793a\u3002\u6b64\u793a\u4f8b\u5728\u6267\u884c View \u65b9\u6cd5\u65f6\u521b\u5efa Information \u7ea7\u522b\u65e5\u5fd7\uff0c\u5982\u679c\u672a\u627e\u5230\u8bf7\u6c42\u7684\u914d\u65b9\uff0c\u5219\u521b\u5efa Warning \u7ea7\u522b\u9519\u8bef\u3002<\/p>\n<p>Listing 26.3 Specifying the log level using extension methods on ILogger<br \/>\n\u6e05\u5355 26.3 \u5728 ILogger \u4e0a\u4f7f\u7528\u6269\u5c55\u65b9\u6cd5\u6307\u5b9a\u65e5\u5fd7\u7ea7\u522b<\/p>\n<pre><code>private readonly ILogger _log;          #A\npublic async IActionResult OnGet(int id)\n{\n    _log.LogInformation(                            #B\n        &quot;Loading recipe with id {RecipeId}&quot;, id);   #B\n\n    Recipe = _service.GetRecipeDetail(id);\n    if (Recipe is null)\n    {\n        _log.LogWarning(                                      #C\n            &quot;Could not find recipe with id {RecipeId}&quot;, id);  #C\n        return NotFound();\n    }\n    return Page();\n}<\/code><\/pre>\n<p>\u2776 An ILogger instance is injected into the Razor Page using constructor injection.<br \/>\n\u4f7f\u7528\u6784\u9020\u51fd\u6570\u6ce8\u5165\u5c06 ILogger \u5b9e\u4f8b\u6ce8\u5165 Razor \u9875\u9762\u3002<\/p>\n<p>\u2777 Writes an Information level log message<br \/>\n\u5199\u5165\u4fe1\u606f\u7ea7\u522b\u65e5\u5fd7\u6d88\u606f<\/p>\n<p>\u2778 Writes a Warning level log message<br \/>\n\u5199\u5165\u8b66\u544a\u7ea7\u522b\u65e5\u5fd7\u6d88\u606f<\/p>\n<p>The LogInformation and LogWarning extension methods create log messages with a log level of Information and Warning, respectively. There are six log levels to choose among, ordered here from most to least serious:<br \/>\nLogInformation \u548c LogWarning \u6269\u5c55\u65b9\u6cd5\u5206\u522b\u521b\u5efa\u65e5\u5fd7\u7ea7\u522b\u4e3a Information \u548c Warning \u7684\u65e5\u5fd7\u6d88\u606f\u3002\u6709\u516d\u4e2a\u65e5\u5fd7\u7ea7\u522b\u53ef\u4f9b\u9009\u62e9\uff0c\u6b64\u5904\u6309\u4ece\u6700\u4e25\u91cd\u5230\u6700\u4e0d\u4e25\u91cd\u7684\u987a\u5e8f\u6392\u5e8f\uff1a<\/p>\n<p>\u2022  Critical\u2014For disastrous failures that may leave the app unable to function correctly, such as out-of-memory exceptions or if the hard drive is out of disk space or the server is on fire.<br \/>\n\u4e25\u91cd - \u5bf9\u4e8e\u53ef\u80fd\u5bfc\u81f4\u5e94\u7528\u7a0b\u5e8f\u65e0\u6cd5\u6b63\u5e38\u5de5\u4f5c\u7684\u707e\u96be\u6027\u6545\u969c\uff0c\u4f8b\u5982\u5185\u5b58\u4e0d\u8db3\u5f02\u5e38\u3001\u786c\u76d8\u9a71\u52a8\u5668\u78c1\u76d8\u7a7a\u95f4\u4e0d\u8db3\u6216\u670d\u52a1\u5668\u7740\u706b\u3002<\/p>\n<p>\u2022  Error\u2014For errors and exceptions that you can\u2019t handle gracefully, such as exceptions thrown when saving an edited entity in EF Core. The operation failed, but the app can continue to function for other requests and users.<br \/>\n\u9519\u8bef - \u5bf9\u4e8e\u65e0\u6cd5\u6b63\u5e38\u5904\u7406\u7684\u9519\u8bef\u548c\u5f02\u5e38\uff0c\u4f8b\u5982\u5728 EF Core \u4e2d\u4fdd\u5b58\u5df2\u7f16\u8f91\u7684\u5b9e\u4f53\u65f6\u5f15\u53d1\u7684\u5f02\u5e38\u3002\u4f5c\u5931\u8d25\uff0c\u4f46\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u7ee7\u7eed\u4e3a\u5176\u4ed6\u8bf7\u6c42\u548c\u7528\u6237\u8fd0\u884c\u3002<\/p>\n<p>\u2022  Warning\u2014For when an unexpected or error condition arises that you can work around. You might log a Warning for handled exceptions or when an entity isn\u2019t found, as in listing 26.3.<br \/>\n\u201c\u8b66\u544a\u201d\uff08Warning\uff09 - \u5f53\u51fa\u73b0\u53ef\u89e3\u51b3\u7684\u610f\u5916\u6216\u9519\u8bef\u60c5\u51b5\u65f6\u3002\u5bf9\u4e8e\u5df2\u5904\u7406\u7684\u5f02\u5e38\u6216\u672a\u627e\u5230\u5b9e\u4f53\uff0c\u60a8\u53ef\u4ee5\u8bb0\u5f55 Warning\uff0c\u5982\u6e05\u5355 26.3 \u6240\u793a\u3002<\/p>\n<p>\u2022  Information\u2014For tracking normal application flow, such as logging when a user signs in or when they view a specific page in your app. Typically these log messages provide context when you need to understand the steps leading up to an error message.<br \/>\n\u4fe1\u606f - \u7528\u4e8e\u8ddf\u8e2a\u6b63\u5e38\u7684\u5e94\u7528\u7a0b\u5e8f\u6d41\uff0c\u4f8b\u5982\u5728\u7528\u6237\u767b\u5f55\u6216\u67e5\u770b\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u7279\u5b9a\u9875\u9762\u65f6\u8fdb\u884c\u65e5\u5fd7\u8bb0\u5f55\u3002\u901a\u5e38\uff0c\u5f53\u60a8\u9700\u8981\u4e86\u89e3\u5bfc\u81f4\u9519\u8bef\u6d88\u606f\u7684\u6b65\u9aa4\u65f6\uff0c\u8fd9\u4e9b\u65e5\u5fd7\u6d88\u606f\u4f1a\u63d0\u4f9b\u4e0a\u4e0b\u6587\u3002<\/p>\n<p>\u2022  Debug\u2014For tracking detailed information that\u2019s particularly useful during development. Generally, this level has only short-term usefulness.<br \/>\n\u8c03\u8bd5 \uff08Debug\uff09 - \u7528\u4e8e\u8ddf\u8e2a\u5f00\u53d1\u8fc7\u7a0b\u4e2d\u7279\u522b\u6709\u7528\u7684\u8be6\u7ec6\u4fe1\u606f\u3002\u4e00\u822c\u6765\u8bf4\uff0c\u8fd9\u4e2a\u7ea7\u522b\u53ea\u6709\u77ed\u671f\u7684\u7528\u5904\u3002<\/p>\n<p>\u2022  Trace\u2014For tracking extremely detailed information, which may contain sensitive information like passwords or keys. It\u2019s rarely used and not used at all by the framework libraries.<br \/>\n\u8ddf\u8e2a - \u7528\u4e8e\u8ddf\u8e2a\u6781\u5176\u8be6\u7ec6\u7684\u4fe1\u606f\uff0c\u5176\u4e2d\u53ef\u80fd\u5305\u542b\u5bc6\u7801\u6216\u5bc6\u94a5\u7b49\u654f\u611f\u4fe1\u606f\u3002\u5b83\u5f88\u5c11\u88ab\u6846\u67b6\u5e93\u4f7f\u7528\uff0c\u4e5f\u6839\u672c\u4e0d\u88ab\u4f7f\u7528\u3002<\/p>\n<p>Think of these log levels in terms of a pyramid, as shown in figure 26.5. As you progress down the log levels, the importance of the messages goes down, but the frequency goes up. Typically, you\u2019ll find many Debug level log messages in your application, but (I hope) few Critical- or Error-level messages.<br \/>\n\u5c06\u8fd9\u4e9b\u5bf9\u6570\u7ea7\u522b\u60f3\u8c61\u6210\u91d1\u5b57\u5854\uff0c\u5982\u56fe 26.5 \u6240\u793a\u3002\u968f\u7740\u65e5\u5fd7\u7ea7\u522b\u7684\u964d\u4f4e\uff0c\u6d88\u606f\u7684\u91cd\u8981\u6027\u4f1a\u4e0b\u964d\uff0c\u4f46\u9891\u7387\u4f1a\u4e0a\u5347\u3002\u901a\u5e38\uff0c\u60a8\u4f1a\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u627e\u5230\u8bb8\u591a Debug \u7ea7\u522b\u7684\u65e5\u5fd7\u6d88\u606f\uff0c\u4f46 \uff08\u6211\u5e0c\u671b\uff09 \u5f88\u5c11\u7684 Critical- \u6216 Error \u7ea7\u522b\u7684\u6d88\u606f\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2605.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 26.5 The pyramid of log levels. Logs with a level near the base of the pyramid are used more frequently but are less important. Logs with a level near the top should be rare but are important.<br \/>\n\u56fe 26.5 \u5bf9\u6570\u6c34\u5e73\u7684\u91d1\u5b57\u5854\u3002\u6c34\u5e73\u4eea\u9760\u8fd1\u91d1\u5b57\u5854\u5e95\u90e8\u7684\u539f\u6728\u4f7f\u7528\u9891\u7387\u66f4\u9ad8\uff0c\u4f46\u4e0d\u592a\u91cd\u8981\u3002\u7ea7\u522b\u63a5\u8fd1\u9876\u90e8\u7684\u65e5\u5fd7\u5e94\u8be5\u5f88\u5c11\u89c1\uff0c\u4f46\u5f88\u91cd\u8981\u3002<\/p>\n<p>This pyramid shape will become more meaningful when we look at filtering in section 26.4. When an app is in production, you typically don\u2019t want to record all the Debug-level messages generated by your application. The sheer volume of messages would be overwhelming to sort through and could end up filling your disk with messages that say \u201cEverything\u2019s OK!\u201d Additionally, Trace messages shouldn\u2019t be enabled in production, as they may leak sensitive data. By filtering out the lower log levels, you can ensure that you generate a sane number of logs in production but have access to all the log levels in development.<br \/>\n\u5f53\u6211\u4eec\u67e5\u770b 26.4 \u8282\u4e2d\u7684\u8fc7\u6ee4\u65f6\uff0c\u8fd9\u4e2a\u91d1\u5b57\u5854\u5f62\u72b6\u5c06\u53d8\u5f97\u66f4\u52a0\u6709\u610f\u4e49\u3002\u5f53\u5e94\u7528\u7a0b\u5e8f\u5904\u4e8e\u751f\u4ea7\u73af\u5883\u4e2d\u65f6\uff0c\u60a8\u901a\u5e38\u4e0d\u5e0c\u671b\u8bb0\u5f55\u5e94\u7528\u7a0b\u5e8f\u751f\u6210\u7684\u6240\u6709 Debug \u7ea7\u522b\u6d88\u606f\u3002\u5e9e\u5927\u7684\u6d88\u606f\u91cf\u4f1a\u8ba9\u4eba\u4e0d\u77e5\u6240\u63aa\uff0c\u6700\u7ec8\u53ef\u80fd\u4f1a\u7528\u201c\u4e00\u5207\u90fd\u5f88\u597d\u201d\u7684\u6d88\u606f\u586b\u6ee1\u60a8\u7684\u78c1\u76d8\u3002\u6b64\u5916\uff0c\u4e0d\u5e94\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u542f\u7528 Trace \u6d88\u606f\uff0c\u56e0\u4e3a\u5b83\u4eec\u53ef\u80fd\u4f1a\u6cc4\u9732\u654f\u611f\u6570\u636e\u3002\u901a\u8fc7\u7b5b\u9009\u51fa\u8f83\u4f4e\u7684\u65e5\u5fd7\u7ea7\u522b\uff0c\u60a8\u53ef\u4ee5\u786e\u4fdd\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u751f\u6210\u4e00\u5b9a\u6570\u91cf\u7684\u65e5\u5fd7\uff0c\u4f46\u53ef\u4ee5\u8bbf\u95ee\u5f00\u53d1\u4e2d\u7684\u6240\u6709\u65e5\u5fd7\u7ea7\u522b\u3002<\/p>\n<p>In general, higher-level logs are more important than lower-level logs, so a Warning log is more important than an Information log, but there\u2019s another aspect to consider. Where the log came from, or who created the log, is a key piece of information that\u2019s recorded with each log message and is called the category.<br \/>\n\u901a\u5e38\uff0c\u8f83\u9ad8\u7ea7\u522b\u7684\u65e5\u5fd7\u6bd4\u8f83\u4f4e\u7ea7\u522b\u7684\u65e5\u5fd7\u66f4\u91cd\u8981\uff0c\u56e0\u6b64 Warning \u65e5\u5fd7\u6bd4 Information \u65e5\u5fd7\u66f4\u91cd\u8981\uff0c\u4f46\u8fd8\u6709\u53e6\u4e00\u4e2a\u65b9\u9762\u9700\u8981\u8003\u8651\u3002\u65e5\u5fd7\u7684\u6765\u6e90\u6216\u65e5\u5fd7\u7684\u521b\u5efa\u8005\u662f\u6bcf\u6761\u65e5\u5fd7\u6d88\u606f\u4e2d\u8bb0\u5f55\u7684\u5173\u952e\u4fe1\u606f\uff0c\u79f0\u4e3a\u7c7b\u522b\u3002<\/p>\n<h3>26.2.2 Log category: Which component created the log<\/h3>\n<p>26.2.2 \u65e5\u5fd7\u7c7b\u522b\uff1a\u54ea\u4e2a\u7ec4\u4ef6\u521b\u5efa\u4e86\u65e5\u5fd7<\/p>\n<p>As well as a log level, every log message also has a category. You set the log level independently for every log message, but the category is set when you create the ILogger instance. Like log levels, the category is particularly useful for filtering, as you\u2019ll see in section 26.4. It\u2019s written to every log message, as shown in figure 26.6.<br \/>\n\u9664\u4e86\u65e5\u5fd7\u7ea7\u522b\u5916\uff0c\u6bcf\u6761\u65e5\u5fd7\u6d88\u606f\u4e5f\u6709\u4e00\u4e2a\u7c7b\u522b\u3002\u60a8\u53ef\u4ee5\u4e3a\u6bcf\u4e2a\u65e5\u5fd7\u6d88\u606f\u5355\u72ec\u8bbe\u7f6e\u65e5\u5fd7\u7ea7\u522b\uff0c\u4f46\u7c7b\u522b\u662f\u5728\u521b\u5efa ILogger \u5b9e\u4f8b\u65f6\u8bbe\u7f6e\u7684\u3002\u4e0e\u65e5\u5fd7\u7ea7\u522b\u4e00\u6837\uff0c\u8be5\u7c7b\u522b\u5bf9\u4e8e\u8fc7\u6ee4\u7279\u522b\u6709\u7528\uff0c\u5982\u7b2c 26.4 \u8282\u6240\u793a\u3002\u5b83\u88ab\u5199\u5165\u6bcf\u4e2a\u65e5\u5fd7\u6d88\u606f\uff0c\u5982\u56fe 26.6 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2606.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 26.6 Every log message has an associated category, which is typically the class name of the component creating the log. The default console logging provider outputs the log category for every log.<br \/>\n\u56fe 26.6 \u6bcf\u6761\u65e5\u5fd7\u6d88\u606f\u90fd\u6709\u4e00\u4e2a\u5173\u8054\u7684\u7c7b\u522b\uff0c\u901a\u5e38\u662f\u521b\u5efa\u65e5\u5fd7\u7684\u7ec4\u4ef6\u7684\u7c7b\u540d\u3002\u9ed8\u8ba4\u63a7\u5236\u53f0\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u8f93\u51fa\u6bcf\u4e2a\u65e5\u5fd7\u7684\u65e5\u5fd7\u7c7b\u522b\u3002<\/p>\n<p>The category is a string, so you can set it to anything, but the convention is to set it to the fully qualified name of the type that\u2019s using ILogger. In section 26.2 I achieved this by injecting ILogger<T> into RecipeController; the generic parameter T is used to set the category of the ILogger.<br \/>\ncategory \u662f\u4e00\u4e2a\u5b57\u7b26\u4e32\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u5c06\u5176\u8bbe\u7f6e\u4e3a\u4efb\u4f55\u503c\uff0c\u4f46\u60ef\u4f8b\u662f\u5c06\u5176\u8bbe\u7f6e\u4e3a\u4f7f\u7528 ILogger \u7684\u7c7b\u578b\u7684\u5b8c\u5168\u9650\u5b9a\u540d\u79f0\u3002\u5728\u7b2c 26.2 \u8282\u4e2d\uff0c\u6211\u901a\u8fc7\u5c06 ILogger \u6ce8\u5165 RecipeController \u6765\u5b9e\u73b0\u8fd9\u4e00\u70b9;\u6cdb\u578b\u53c2\u6570 T \u7528\u4e8e\u8bbe\u7f6e ILogger \u7684\u7c7b\u522b\u3002<\/p>\n<p>Alternatively, you can inject ILoggerFactory into your methods and pass an explicit category when creating an ILogger instance, as shown in the following listing. This lets you change the category to an arbitrary string.<br \/>\n\u6216\u8005\uff0c\u53ef\u4ee5\u5c06 ILoggerFactory \u6ce8\u5165\u5230\u65b9\u6cd5\u4e2d\uff0c\u5e76\u5728\u521b\u5efa ILogger \u5b9e\u4f8b\u65f6\u4f20\u9012\u663e\u5f0f\u7c7b\u522b\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002\u8fd9\u5141\u8bb8\u60a8\u5c06\u7c7b\u522b\u66f4\u6539\u4e3a\u4efb\u610f\u5b57\u7b26\u4e32\u3002<\/p>\n<p>Listing 26.4 Injecting ILoggerFactory to use a custom category<br \/>\n\u5217\u8868 26.4 \u6ce8\u5165 ILoggerFactory \u4ee5\u4f7f\u7528\u81ea\u5b9a\u4e49\u7c7b\u522b<\/p>\n<pre><code>public class RecipeService\n{\n    private readonly ILogger _log;\n    public RecipeService(ILoggerFactory factory)    #A\n    {\n        _log = factory.CreateLogger(&quot;RecipeApp.RecipeService&quot;);     #B\n    }\n}<\/code><\/pre>\n<p>\u2776 Injects an ILoggerFactory instead of an ILogger directly<br \/>\n\u76f4\u63a5\u6ce8\u5165 ILoggerFactory \u800c\u4e0d\u662f ILogger<\/p>\n<p>\u2777 Passes a category as a string when calling CreateLogger<br \/>\n\u8c03\u7528 CreateLogger \u65f6\u5c06\u7c7b\u522b\u4f5c\u4e3a\u5b57\u7b26\u4e32\u4f20\u9012<\/p>\n<p>There is also an overload of CreateLogger() with a generic parameter that uses the provided class to set the category. If the RecipeService in listing 26.4 were in the RecipeApp namespace, the CreateLogger call could be written equivalently as<br \/>\n\u8fd8\u6709\u4e00\u4e2a CreateLogger\uff08\uff09 \u7684\u91cd\u8f7d\uff0c\u5176\u4e2d\u5305\u542b\u4e00\u4e2a\u6cdb\u578b\u53c2\u6570\uff0c\u8be5\u53c2\u6570\u4f7f\u7528\u63d0\u4f9b\u7684\u7c7b\u6765\u8bbe\u7f6e\u7c7b\u522b\u3002\u5982\u679c\u6e05\u5355 26.4 \u4e2d\u7684 RecipeService \u4f4d\u4e8e RecipeApp \u547d\u540d\u7a7a\u95f4\u4e2d\uff0c\u5219 CreateLogger \u8c03\u7528\u53ef\u4ee5\u7b49\u6548\u5730\u5199\u4e3a<\/p>\n<pre><code>_log = factory.CreateLogger&lt;RecipeService&gt;();<\/code><\/pre>\n<p>Similarly, the final ILogger instance created by this call would be the same as if you\u2019d directly injected <code>ILogger&lt;RecipeService&gt;<\/code> instead of ILoggerFactory.<br \/>\n\u540c\u6837\uff0c\u6b64\u8c03\u7528\u521b\u5efa\u7684\u6700\u7ec8 ILogger \u5b9e\u4f8b\u4e0e\u76f4\u63a5\u6ce8\u5165 <code>ILogger&lt;RecipeService&gt;<\/code>  \u800c\u4e0d\u662f ILoggerFactory \u65f6\u76f8\u540c\u3002<\/p>\n<p><b>TIP<\/b> Unless you\u2019re using heavily customized categories for some reason, favor injecting <code>ILogger&lt;T&gt;<\/code> into your methods over ILoggerFactory.<br \/>\n\u63d0\u793a:\u9664\u975e\u51fa\u4e8e\u67d0\u79cd\u539f\u56e0\u4f7f\u7528\u9ad8\u5ea6\u81ea\u5b9a\u4e49\u7684\u7c7b\u522b\uff0c\u5426\u5219\u6700\u597d\u5c06 <code>ILogger&lt;T&gt;<\/code> \u6ce8\u5165\u5230\u65b9\u6cd5\u4e2d\uff0c\u800c\u4e0d\u662f ILoggerFactory\u3002<\/p>\n<p>The final compulsory part of every log entry is fairly obvious: the log message. At the simplest level, this can be any string, but it\u2019s worth thinking carefully about what information would be useful to record\u2014anything that will help you diagnose problems later on.<br \/>\n\u6bcf\u4e2a\u65e5\u5fd7\u6761\u76ee\u7684\u6700\u540e\u4e00\u4e2a\u5f3a\u5236\u90e8\u5206\u76f8\u5f53\u660e\u663e\uff1a\u65e5\u5fd7\u6d88\u606f\u3002\u5728\u6700\u7b80\u5355\u7684\u7ea7\u522b\u4e0a\uff0c\u8fd9\u53ef\u4ee5\u662f\u4efb\u4f55\u5b57\u7b26\u4e32\uff0c\u4f46\u503c\u5f97\u4ed4\u7ec6\u8003\u8651\u8bb0\u5f55\u54ea\u4e9b\u4fe1\u606f\u662f\u6709\u7528\u7684 \u2014 \u4efb\u4f55\u6709\u52a9\u4e8e\u60a8\u7a0d\u540e\u8bca\u65ad\u95ee\u9898\u7684\u4fe1\u606f\u3002<\/p>\n<h3>26.2.3 Formatting messages and capturing parameter values<\/h3>\n<p>26.2.3 \u683c\u5f0f\u5316\u6d88\u606f\u548c\u6355\u83b7\u53c2\u6570\u503c<\/p>\n<p>Whenever you create a log entry, you must provide a message. This can be any string you like, but as you saw in listing 26.2, you can also include placeholders indicated by braces, {}, in the message string:<br \/>\n\u65e0\u8bba\u4f55\u65f6\u521b\u5efa\u65e5\u5fd7\u6761\u76ee\uff0c\u90fd\u5fc5\u987b\u63d0\u4f9b\u4e00\u6761\u6d88\u606f\u3002\u8fd9\u53ef\u4ee5\u662f\u4f60\u559c\u6b22\u7684\u4efb\u4f55\u5b57\u7b26\u4e32\uff0c\u4f46\u6b63\u5982\u4f60\u5728 \u6e05\u5355 26.2 \u4e2d\u770b\u5230\u7684\uff0c\u4f60\u4e5f\u53ef\u4ee5\u5728\u6d88\u606f\u5b57\u7b26\u4e32\u4e2d\u5305\u542b\u7531\u5927\u62ec\u53f7 {} \u6307\u793a\u7684\u5360\u4f4d\u7b26\uff1a<\/p>\n<pre><code>_log.LogInformation(&quot;Loaded {RecipeCount} recipes&quot;, Recipes.Count);<\/code><\/pre>\n<p>Including a placeholder and a parameter value in your log message effectively creates a key-value pair, which some logging providers can store as additional information associated with the log. The previous log message would assign the value of Recipes.Count to a key, RecipeCount, and the log message itself is generated by replacing the placeholder with the parameter value, to give the following (where Recipes.Count=3):<br \/>\n\u5728\u65e5\u5fd7\u6d88\u606f\u4e2d\u5305\u542b\u5360\u4f4d\u7b26\u548c\u53c2\u6570\u503c\u53ef\u4ee5\u6709\u6548\u5730\u521b\u5efa\u4e00\u4e2a\u952e\u503c\u5bf9\uff0c\u4e00\u4e9b\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u5546\u53ef\u4ee5\u5c06\u5176\u5b58\u50a8\u4e3a\u4e0e\u65e5\u5fd7\u5173\u8054\u7684\u5176\u4ed6\u4fe1\u606f\u3002\u524d\u9762\u7684\u65e5\u5fd7\u6d88\u606f\u4f1a\u5c06 Recipes.Count \u7684\u503c\u5206\u914d\u7ed9\u952e RecipeCount\uff0c\u5e76\u4e14\u65e5\u5fd7\u6d88\u606f\u672c\u8eab\u662f\u901a\u8fc7\u5c06\u5360\u4f4d\u7b26\u66ff\u6362\u4e3a\u53c2\u6570\u503c\u6765\u751f\u6210\u7684\uff0c\u4ee5\u7ed9\u51fa\u4ee5\u4e0b\u5185\u5bb9\uff08\u5176\u4e2d Recipes.Count=3\uff09\uff1a<\/p>\n<pre><code>&quot;Loaded 3 recipes&quot;<\/code><\/pre>\n<p>You can include multiple placeholders in a log message, and they\u2019re associated with the additional parameters passed to the log method. The order of the placeholders in the format string must match the order of the parameters you provide.<br \/>\n\u60a8\u53ef\u4ee5\u5728\u65e5\u5fd7\u6d88\u606f\u4e2d\u5305\u542b\u591a\u4e2a\u5360\u4f4d\u7b26\uff0c\u5b83\u4eec\u4e0e\u4f20\u9012\u7ed9 log \u65b9\u6cd5\u7684\u5176\u4ed6\u53c2\u6570\u76f8\u5173\u8054\u3002\u683c\u5f0f\u5b57\u7b26\u4e32\u4e2d\u5360\u4f4d\u7b26\u7684\u987a\u5e8f\u5fc5\u987b\u4e0e\u60a8\u63d0\u4f9b\u7684\u53c2\u6570\u7684\u987a\u5e8f\u5339\u914d\u3002<\/p>\n<p><b>WARNING<\/b> You must pass at least as many parameters to the log method as there are placeholders in the message. If you don\u2019t pass enough parameters, you\u2019ll get an exception at runtime.<br \/>\n\u8b66\u544a:\u5411 log \u65b9\u6cd5\u4f20\u9012\u7684\u53c2\u6570\u5fc5\u987b\u81f3\u5c11\u4e0e\u6d88\u606f\u4e2d\u7684\u5360\u4f4d\u7b26\u6570\u91cf\u76f8\u540c\u3002\u5982\u679c\u60a8\u6ca1\u6709\u4f20\u9012\u8db3\u591f\u7684\u53c2\u6570\uff0c\u60a8\u5c06\u5728\u8fd0\u884c\u65f6\u6536\u5230\u5f02\u5e38\u3002<\/p>\n<p>For example, the log message<br \/>\n\u4f8b\u5982\uff0c\u65e5\u5fd7\u6d88\u606f<\/p>\n<pre><code>_log.LogInformation(&quot;User {UserId} loaded recipe {RecipeId}&quot;, 123, 456)<\/code><\/pre>\n<p>would create the parameters UserId=123 and RecipeId=456. Structured logging providers could store these values, in addition to the formatted log message &quot;User 123 loaded recipe 456&quot;. This makes it easier to search the logs for a particular UserId or RecipeId.<br \/>\n\u5c06\u521b\u5efa\u53c2\u6570 UserId=123 \u548c RecipeId=456\u3002\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u53ef\u4ee5\u5b58\u50a8\u8fd9\u4e9b\u503c\uff0c\u4ee5\u53ca\u683c\u5f0f\u5316\u7684\u65e5\u5fd7\u6d88\u606f\u201cUser 123 loaded recipe 456\u201d\u3002\u8fd9\u6837\u53ef\u4ee5\u66f4\u8f7b\u677e\u5730\u5728\u65e5\u5fd7\u4e2d\u641c\u7d22\u7279\u5b9a UserId \u6216 RecipeId\u3002<\/p>\n<p><b>DEFINITION<\/b> Structured or semantic logging attaches additional structure to log messages to make them more easily searchable and filterable. Rather than storing only text, it stores additional contextual information, typically as key-value pairs. JavaScript Object Notation (JSON) is a common format used for structured log messages.<br \/>\n\u5b9a\u4e49:\u7ed3\u6784\u5316\u6216\u8bed\u4e49\u65e5\u5fd7\u8bb0\u5f55\u5c06\u5176\u4ed6\u7ed3\u6784\u9644\u52a0\u5230\u65e5\u5fd7\u6d88\u606f\uff0c\u4f7f\u5176\u66f4\u6613\u4e8e\u641c\u7d22\u548c\u7b5b\u9009\u3002\u5b83\u4e0d\u4ec5\u5b58\u50a8\u6587\u672c\uff0c\u8fd8\u5b58\u50a8\u5176\u4ed6\u4e0a\u4e0b\u6587\u4fe1\u606f\uff0c\u901a\u5e38\u4f5c\u4e3a\u952e\u503c\u5bf9\u3002JavaScript \u5bf9\u8c61\u8868\u793a\u6cd5 \uff08JSON\uff09 \u662f\u7528\u4e8e\u7ed3\u6784\u5316\u65e5\u5fd7\u6d88\u606f\u7684\u5e38\u7528\u683c\u5f0f\u3002<\/p>\n<p>Not all logging providers use semantic logging. The default console logging provider format doesn\u2019t, for example; the message is formatted to replace the placeholders, but there\u2019s no way of searching the console by key-value.<br \/>\n\u5e76\u975e\u6240\u6709\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u90fd\u4f7f\u7528\u8bed\u4e49\u65e5\u5fd7\u8bb0\u5f55\u3002\u4f8b\u5982\uff0c\u9ed8\u8ba4\u7684\u63a7\u5236\u53f0\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u683c\u5f0f\u4e0d\u4f1a;\u6d88\u606f\u7684\u683c\u5f0f\u8bbe\u7f6e\u4e3a\u66ff\u6362\u5360\u4f4d\u7b26\uff0c\u4f46\u65e0\u6cd5\u6309 Key-Value \u641c\u7d22\u63a7\u5236\u53f0\u3002<\/p>\n<p><b>TIP<\/b> You can enable JSON output for the console provider by calling WebApplicationBuilder.Logging.AddJsonConsole(). You can further customize the format of the provider, as described in the documentation at <a href=\"http:\/\/mng.bz\/QP8v\">http:\/\/mng.bz\/QP8v<\/a>.<br \/>\n\u63d0\u793a:\u60a8\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528 WebApplicationBuilder.Logging.AddJsonConsole\uff08\uff09 \u4e3a\u63a7\u5236\u53f0\u63d0\u4f9b\u7a0b\u5e8f\u542f\u7528 JSON \u8f93\u51fa\u3002\u60a8\u53ef\u4ee5\u8fdb\u4e00\u6b65\u81ea\u5b9a\u4e49\u63d0\u4f9b\u7a0b\u5e8f\u7684\u683c\u5f0f\uff0c\u5982 <a href=\"http:\/\/mng.bz\/QP8v\">http:\/\/mng.bz\/QP8v<\/a> \u4e2d\u7684\u6587\u6863\u4e2d\u6240\u8ff0\u3002<\/p>\n<p>Even if you\u2019re not using structured logging initially, I recommend writing your log messages as though you are, with explicit placeholders and parameters. That way, if you decide to add a structured logging provider later, you\u2019ll immediately see the benefits. Additionally, I find that thinking about the parameters that you can log in this way prompts you to record more parameter values instead of only a log message. There\u2019s nothing more frustrating than seeing a message like &quot;Cannot insert record due to duplicate key&quot; but not having the key value logged!<br \/>\n\u5373\u4f7f\u60a8\u6700\u521d\u6ca1\u6709\u4f7f\u7528\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\uff0c\u6211\u4e5f\u5efa\u8bae\u60a8\u50cf\u4f7f\u7528\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u4e00\u6837\u7f16\u5199\u65e5\u5fd7\u6d88\u606f\uff0c\u5e76\u4f7f\u7528\u660e\u786e\u7684\u5360\u4f4d\u7b26\u548c\u53c2\u6570\u3002\u8fd9\u6837\uff0c\u5982\u679c\u60a8\u51b3\u5b9a\u7a0d\u540e\u6dfb\u52a0\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u5546\uff0c\u60a8\u5c06\u7acb\u5373\u770b\u5230\u597d\u5904\u3002\u6b64\u5916\uff0c\u6211\u53d1\u73b0\uff0c\u8003\u8651\u53ef\u4ee5\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u8bb0\u5f55\u7684\u53c2\u6570\u4f1a\u63d0\u793a\u60a8\u8bb0\u5f55\u66f4\u591a\u53c2\u6570\u503c\uff0c\u800c\u4e0d\u4ec5\u4ec5\u662f\u65e5\u5fd7\u6d88\u606f\u3002\u6ca1\u6709\u4ec0\u4e48\u6bd4\u770b\u5230\u7c7b\u4f3c \u201cCannot insert record due to duplicate key\u201d \u7684\u6d88\u606f\u4f46\u6ca1\u6709\u8bb0\u5f55\u952e\u503c\u66f4\u4ee4\u4eba\u6cae\u4e27\u7684\u4e86\uff01<\/p>\n<p><b>TIP<\/b> Generally speaking, I\u2019m a fan of C#\u2019s interpolated strings, but don\u2019t use them for your log messages when a placeholder and parameter would also make sense. Using placeholders instead of interpolated strings gives you the same output message but also creates key-value pairs that can be searched later.<br \/>\n\u63d0\u793a:\u4e00\u822c\u6765\u8bf4\uff0c\u6211\u662f C# \u7684\u63d2\u503c\u5b57\u7b26\u4e32\u7684\u7c89\u4e1d\uff0c\u4f46\u5f53\u5360\u4f4d\u7b26\u548c\u53c2\u6570\u4e5f\u6709\u610f\u4e49\u65f6\uff0c\u4e0d\u8981\u5c06\u5b83\u4eec\u7528\u4e8e\u65e5\u5fd7\u6d88\u606f\u3002\u4f7f\u7528\u5360\u4f4d\u7b26\u800c\u4e0d\u662f\u5185\u63d2\u5b57\u7b26\u4e32\u4f1a\u4e3a\u60a8\u63d0\u4f9b\u76f8\u540c\u7684\u8f93\u51fa\u6d88\u606f\uff0c\u4f46\u4e5f\u4f1a\u521b\u5efa\u7a0d\u540e\u53ef\u641c\u7d22\u7684\u952e\u503c\u5bf9\u3002<\/p>\n<p>We\u2019ve looked a lot at how you can create log messages in your app, but we haven\u2019t focused on where those logs are written. In the next section we\u2019ll look at the built-in ASP.NET Core logging providers, how they\u2019re configured, and how you can add a third-party provider.<br \/>\n\u6211\u4eec\u5df2\u7ecf\u7814\u7a76\u4e86\u5f88\u591a\u5173\u4e8e\u5982\u4f55\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u521b\u5efa\u65e5\u5fd7\u6d88\u606f\u7684\u7814\u7a76\uff0c\u4f46\u6211\u4eec\u6ca1\u6709\u5173\u6ce8\u8fd9\u4e9b\u65e5\u5fd7\u7684\u5199\u5165\u4f4d\u7f6e\u3002\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u5185\u7f6e\u7684 ASP.NET Core \u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u3001\u5b83\u4eec\u7684\u914d\u7f6e\u65b9\u5f0f\u4ee5\u53ca\u5982\u4f55\u6dfb\u52a0\u7b2c\u4e09\u65b9\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<h2>26.3 Controlling where logs are written using logging providers<\/h2>\n<p>26.3 \u4f7f\u7528\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u63a7\u5236\u65e5\u5fd7\u7684\u5199\u5165\u4f4d\u7f6e<\/p>\n<p>In this section you\u2019ll learn how to control where your log messages are written by adding ILoggerProviders to your application. As an example, you\u2019ll see how to add a simple file logger provider that writes your log messages to a file, in addition to the existing console logger provider.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u901a\u8fc7\u5c06 ILoggerProviders \u6dfb\u52a0\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u6765\u63a7\u5236\u65e5\u5fd7\u6d88\u606f\u7684\u5199\u5165\u4f4d\u7f6e\u3002\u4f8b\u5982\uff0c\u9664\u4e86\u73b0\u6709\u7684\u63a7\u5236\u53f0\u8bb0\u5f55\u5668\u63d0\u4f9b\u7a0b\u5e8f\u4e4b\u5916\uff0c\u60a8\u8fd8\u5c06\u4e86\u89e3\u5982\u4f55\u6dfb\u52a0\u4e00\u4e2a\u7b80\u5355\u7684\u6587\u4ef6\u8bb0\u5f55\u5668\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u7528\u4e8e\u5c06\u65e5\u5fd7\u6d88\u606f\u5199\u5165\u6587\u4ef6\u3002<\/p>\n<p>Up to this point, we\u2019ve been writing all our log messages to the console. If you\u2019ve run any ASP.NET Core sample apps locally, you\u2019ll probably have seen the log messages written to the console window.<br \/>\n\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u6211\u4eec\u4e00\u76f4\u5728\u5c06\u6240\u6709\u65e5\u5fd7\u6d88\u606f\u5199\u5165\u63a7\u5236\u53f0\u3002\u5982\u679c\u60a8\u5728\u672c\u5730\u8fd0\u884c\u4e86\u4efb\u4f55 ASP.NET Core \u793a\u4f8b\u5e94\u7528\u7a0b\u5e8f\uff0c\u5219\u53ef\u80fd\u5df2\u7ecf\u770b\u5230\u5199\u5165\u63a7\u5236\u53f0\u7a97\u53e3\u7684\u65e5\u5fd7\u6d88\u606f\u3002<\/p>\n<p><b>NOTE<\/b> If you\u2019re using Visual Studio and debugging by using the Internet Information Services (IIS) Express option, you won\u2019t see the console window (though the log messages are written to the Debug Output window instead).<br \/>\n\u6ce8\u610f:\u5982\u679c\u60a8\u4f7f\u7528\u7684\u662f Visual Studio \u5e76\u4f7f\u7528 Internet Information Services \uff08IIS\uff09 Express \u9009\u9879\u8fdb\u884c\u8c03\u8bd5\uff0c\u5219\u4e0d\u4f1a\u770b\u5230\u63a7\u5236\u53f0\u7a97\u53e3\uff08\u5c3d\u7ba1\u65e5\u5fd7\u6d88\u606f\u4f1a\u5199\u5165\u201c\u8c03\u8bd5\u8f93\u51fa\u201d\u7a97\u53e3\uff09\u3002<\/p>\n<p>Writing log messages to the console is great when you\u2019re debugging, but it\u2019s not much use for production. No one\u2019s going to be monitoring a console window on a server, and the logs wouldn\u2019t be saved anywhere or be searchable. Clearly, you\u2019ll need to write your production logs somewhere else.<br \/>\n\u5728\u8c03\u8bd5\u65f6\uff0c\u5c06\u65e5\u5fd7\u6d88\u606f\u5199\u5165\u63a7\u5236\u53f0\u975e\u5e38\u6709\u7528\uff0c\u4f46\u5bf9\u751f\u4ea7\u6ca1\u6709\u591a\u5927\u7528\u5904\u3002\u6ca1\u6709\u4eba\u4f1a\u76d1\u63a7\u670d\u52a1\u5668\u4e0a\u7684\u63a7\u5236\u53f0\u7a97\u53e3\uff0c\u65e5\u5fd7\u4e0d\u4f1a\u4fdd\u5b58\u5728\u4efb\u4f55\u5730\u65b9\uff0c\u4e5f\u65e0\u6cd5\u641c\u7d22\u3002\u663e\u7136\uff0c\u60a8\u9700\u8981\u5c06\u751f\u4ea7\u65e5\u5fd7\u5199\u5165\u5176\u4ed6\u4f4d\u7f6e\u3002<\/p>\n<p>As you saw in section 26.1, logging providers control the destination of your log messages in ASP.NET Core. They take the messages you create using the ILogger interface and write them to an output location, which varies depending on the provider.<br \/>\n\u6b63\u5982\u60a8\u5728\u7b2c 26.1 \u8282\u4e2d\u770b\u5230\u7684\u90a3\u6837\uff0c\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u63a7\u5236 ASP.NET Core \u4e2d\u65e5\u5fd7\u6d88\u606f\u7684\u76ee\u7684\u5730\u3002\u5b83\u4eec\u83b7\u53d6\u60a8\u4f7f\u7528 ILogger \u63a5\u53e3\u521b\u5efa\u7684\u6d88\u606f\uff0c\u5e76\u5c06\u5176\u5199\u5165\u8f93\u51fa\u4f4d\u7f6e\uff0c\u8be5\u4f4d\u7f6e\u56e0\u63d0\u4f9b\u5546\u800c\u5f02\u3002<\/p>\n<p><b>NOTE<\/b> This name always gets to me: the log provider effectively consumes the log messages you create and outputs them to a destination. You can probably see the origin of the name from figure 26.3, but I still find it somewhat counterintuitive.<br \/>\n\u6ce8\u610f:\u6211\u603b\u662f\u80fd\u60f3\u5230\u8fd9\u4e2a\u540d\u5b57\uff1a\u65e5\u5fd7\u63d0\u4f9b\u7a0b\u5e8f\u4f1a\u6709\u6548\u5730\u4f7f\u7528\u60a8\u521b\u5efa\u7684\u65e5\u5fd7\u6d88\u606f\uff0c\u5e76\u5c06\u5b83\u4eec\u8f93\u51fa\u5230\u76ee\u6807\u3002\u4f60\u53ef\u80fd\u53ef\u4ee5\u4ece\u56fe 26.3 \u4e2d\u770b\u5230\u8fd9\u4e2a\u540d\u5b57\u7684\u7531\u6765\uff0c\u4f46\u6211\u4ecd\u7136\u89c9\u5f97\u5b83\u6709\u70b9\u8fdd\u53cd\u76f4\u89c9\u3002<\/p>\n<p>Microsoft has written several first-party log providers for ASP.NET Core that are available out of the box in ASP.NET Core. These providers include<br \/>\nMicrosoft \u4e3a ASP.NET Core \u7f16\u5199\u4e86\u51e0\u4e2a\u7b2c\u4e00\u65b9\u65e5\u5fd7\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u8fd9\u4e9b\u63d0\u4f9b\u7a0b\u5e8f\u5728 ASP.NET Core \u4e2d\u5f00\u7bb1\u5373\u7528\u3002\u8fd9\u4e9b\u63d0\u4f9b\u5546\u5305\u62ec<\/p>\n<p>\u2022  Console provider\u2014Writes messages to the console, as you\u2019ve already seen<br \/>\n\u63a7\u5236\u53f0\u63d0\u4f9b\u7a0b\u5e8f - \u5982\u60a8\u6240\u89c1\uff0c\u5c06\u6d88\u606f\u5199\u5165\u63a7\u5236\u53f0<\/p>\n<p>\u2022  Debug provider\u2014Writes messages to the debug window when you\u2019re debugging an app in Visual Studio or Visual Studio Code, for example<br \/>\n\u8c03\u8bd5\u63d0\u4f9b\u7a0b\u5e8f - \u4f8b\u5982\uff0c\u5f53\u60a8\u5728 Visual Studio \u6216 Visual Studio Code \u4e2d\u8c03\u8bd5\u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u5c06\u6d88\u606f\u5199\u5165\u8c03\u8bd5\u7a97\u53e3<\/p>\n<p>\u2022  EventLog provider\u2014Writes messages to the Windows Event Log and outputs log messages only when running in Windows, as it requires Windows-specific APIs<br \/>\nEventLog \u63d0\u4f9b\u7a0b\u5e8f - \u4ec5\u5728 Windows \u4e2d\u8fd0\u884c\u65f6\u5c06\u6d88\u606f\u5199\u5165 Windows \u4e8b\u4ef6\u65e5\u5fd7\u5e76\u8f93\u51fa\u65e5\u5fd7\u6d88\u606f\uff0c\u56e0\u4e3a\u5b83\u9700\u8981\u7279\u5b9a\u4e8e Windows \u7684 API<\/p>\n<p>\u2022  EventSource provider\u2014Writes messages using Event Tracing for Windows (ETW) or LTTng tracing on Linux<br \/>\nEventSource \u63d0\u4f9b\u7a0b\u5e8f - \u4f7f\u7528 Windows \u4e8b\u4ef6\u8ddf\u8e2a \uff08ETW\uff09 \u6216 Linux \u4e0a\u7684 LTTng \u8ddf\u8e2a\u7f16\u5199\u6d88\u606f<\/p>\n<p>There are also many third-party logging provider implementations, such as an Azure App Service provider, an elmah.io provider, and an Elasticsearch provider. On top of that, there are integrations with other existing logging frameworks like NLog and Serilog. It\u2019s always worth looking to see whether your favorite .NET logging library or service has a provider for ASP.NET Core, as most do.<br \/>\n\u8fd8\u6709\u8bb8\u591a\u7b2c\u4e09\u65b9\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u5b9e\u73b0\uff0c\u4f8b\u5982 Azure \u5e94\u7528\u670d\u52a1\u63d0\u4f9b\u5546\u3001elmah.io \u63d0\u4f9b\u7a0b\u5e8f\u548c Elasticsearch \u63d0\u4f9b\u7a0b\u5e8f\u3002\u6700\u91cd\u8981\u7684\u662f\uff0c\u5b83\u8fd8\u4e0e\u5176\u4ed6\u73b0\u6709\u7684\u65e5\u5fd7\u8bb0\u5f55\u6846\u67b6\uff08\u5982 NLog \u548c Serilog\uff09\u96c6\u6210\u3002\u770b\u770b\u60a8\u6700\u559c\u6b22\u7684 .NET \u65e5\u5fd7\u8bb0\u5f55\u5e93\u6216\u670d\u52a1\u662f\u5426\u50cf\u5927\u591a\u6570\u4e00\u6837\u5177\u6709 ASP.NET Core \u7684\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u59cb\u7ec8\u503c\u5f97\u4e00\u8bd5\u3002<\/p>\n<p><b>TIP<\/b> Serilog (<a href=\"https:\/\/serilog.net\">https:\/\/serilog.net<\/a>) is my go-to logging framework. It\u2019s a mature framework with a huge number of supported destinations for writing logs. See Serilog\u2019s ASP.NET Core integration repository for details on how to use Serilog with ASP.NET Core apps: <a href=\"https:\/\/github.com\/serilog\/serilog-aspnetcore\">https:\/\/github.com\/serilog\/serilog-aspnetcore<\/a>.<br \/>\n\u63d0\u793a:Serilog \uff08<a href=\"https:\/\/serilog.net\">https:\/\/serilog.net<\/a>\uff09 \u662f\u6211\u7684\u9996\u9009\u65e5\u5fd7\u8bb0\u5f55\u6846\u67b6\u3002\u5b83\u662f\u4e00\u4e2a\u6210\u719f\u7684\u6846\u67b6\uff0c\u5177\u6709\u5927\u91cf\u652f\u6301\u5199\u5165\u65e5\u5fd7\u7684\u76ee\u6807\u3002\u6709\u5173\u5982\u4f55\u5c06 Serilog \u4e0e ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u7ed3\u5408\u4f7f\u7528\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605 Serilog \u7684 ASP.NET Core \u96c6\u6210\u5b58\u50a8\u5e93\uff1a<a href=\"https:\/\/github.com\/serilog\/serilog-aspnetcore\">https:\/\/github.com\/serilog\/serilog-aspnetcore<\/a>\u3002<\/p>\n<p>You configure the logging providers for your app in Program.cs. WebApplicationBuilder configures the console and debug providers for your application automatically, but it\u2019s likely that you\u2019ll want to change or add to these.<br \/>\n\u60a8\u53ef\u4ee5\u5728 Program.cs \u4e2d\u4e3a\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u3002WebApplicationBuilder \u4f1a\u81ea\u52a8\u4e3a\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u63a7\u5236\u53f0\u548c\u8c03\u8bd5\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u4f46\u60a8\u53ef\u80fd\u5e0c\u671b\u66f4\u6539\u6216\u6dfb\u52a0\u8fd9\u4e9b\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<p>In this section I show how to add a simple third-party logging provider that writes to a rolling file so our application writes logs to a new file each day. We\u2019ll continue to log using the console and debug providers as well, because they\u2019re more useful than the file provider when developing locally.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u6211\u5c06\u4ecb\u7ecd\u5982\u4f55\u6dfb\u52a0\u4e00\u4e2a\u7b80\u5355\u7684\u7b2c\u4e09\u65b9\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u8be5\u63d0\u4f9b\u7a0b\u5e8f\u5c06\u5199\u5165\u6eda\u52a8\u6587\u4ef6\uff0c\u4ee5\u4fbf\u6211\u4eec\u7684\u5e94\u7528\u7a0b\u5e8f\u6bcf\u5929\u5c06\u65e5\u5fd7\u5199\u5165\u65b0\u6587\u4ef6\u3002\u6211\u4eec\u8fd8\u5c06\u7ee7\u7eed\u4f7f\u7528\u63a7\u5236\u53f0\u548c\u8c03\u8bd5\u63d0\u4f9b\u7a0b\u5e8f\u8fdb\u884c\u65e5\u5fd7\u8bb0\u5f55\uff0c\u56e0\u4e3a\u5728\u672c\u5730\u5f00\u53d1\u65f6\uff0c\u5b83\u4eec\u6bd4\u6587\u4ef6\u63d0\u4f9b\u7a0b\u5e8f\u66f4\u6709\u7528\u3002<\/p>\n<p>To add a third-party logging provider in ASP.NET Core, follow these steps:<br \/>\n\u8981\u5728 ASP.NET Core \u4e2d\u6dfb\u52a0\u7b2c\u4e09\u65b9\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u8bf7\u6267\u884c\u4ee5\u4e0b\u6b65\u9aa4\uff1a<\/p>\n<ol>\n<li>Add the logging provider NuGet package to the solution. I\u2019m going to be using a provider called NetEscapades.Extensions.Logging.RollingFile, which is available on NuGet and GitHub. You can add it to your solution using the NuGet Package Manager in Visual Studio or using the .NET command-line interface (CLI) by running<br \/>\n\u5c06\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f NuGet \u5305\u6dfb\u52a0\u5230\u89e3\u51b3\u65b9\u6848\u4e2d\u3002\u6211\u5c06\u4f7f\u7528\u4e00\u4e2a\u540d\u4e3a NetEscapades.Extensions.Logging.RollingFile \u7684\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u8be5\u63d0\u4f9b\u7a0b\u5e8f\u53ef\u5728 NuGet \u548c GitHub \u4e0a\u627e\u5230\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 Visual Studio \u4e2d\u7684 NuGet \u5305\u7ba1\u7406\u5668\u6216\u4f7f\u7528 .NET \u547d\u4ee4\u884c\u754c\u9762 \uff08CLI\uff09 \u5c06\u5176\u6dfb\u52a0\u5230\u89e3\u51b3\u65b9\u6848\u4e2d\uff0c\u65b9\u6cd5\u662f\u8fd0\u884c<\/li>\n<\/ol>\n<pre><code>dotnet add package NetEscapades.Extensions.Logging.RollingFile<\/code><\/pre>\n<p>from your application\u2019s project folder.<br \/>\n\u4ece\u5e94\u7528\u7a0b\u5e8f\u7684 Project \u6587\u4ef6\u5939\u4e2d\u3002<\/p>\n<ol start=\"2\">\n<li>Add the logging provider to WebApplicationBuilder.Logging. You can add the file provider by calling AddFile(), as shown in the next listing. AddFile() is an extension method provided by the logging provider package to simplify adding the provider to your app.<br \/>\n\u5c06\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230 WebApplicationBuilder.Logging\u3002\u60a8\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528 AddFile\uff08\uff09 \u6765\u6dfb\u52a0\u6587\u4ef6\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u5982\u4e0b\u4e00\u4e2a\u6e05\u5355\u6240\u793a\u3002AddFile\uff08\uff09 \u662f\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u5305\u63d0\u4f9b\u7684\u6269\u5c55\u65b9\u6cd5\uff0c\u7528\u4e8e\u7b80\u5316\u5411\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u63d0\u4f9b\u7a0b\u5e8f\u7684\u8fc7\u7a0b\u3002<\/li>\n<\/ol>\n<p><b>NOTE<\/b> This package is a simple file logging provider, available at <a href=\"http:\/\/mng.bz\/XN5a\">http:\/\/mng.bz\/XN5a<\/a>. It\u2019s based on the Azure App Service logging provider. If you need a more robust package, consider using Serilog\u2019s file providers instead.<br \/>\n\u6ce8\u610f:\u6b64\u5305\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u6587\u4ef6\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u53ef\u4ece <a href=\"http:\/\/mng.bz\/XN5a\">http:\/\/mng.bz\/XN5a<\/a> \u83b7\u53d6\u3002\u5b83\u57fa\u4e8e Azure \u5e94\u7528\u670d\u52a1\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u3002\u5982\u679c\u60a8\u9700\u8981\u66f4\u5065\u58ee\u7684\u5305\uff0c\u8bf7\u8003\u8651\u6539\u7528 Serilog \u7684\u6587\u4ef6\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<p>Listing 26.5 Adding a third-party logging provider to WebApplicationBuilder<br \/>\n\u6e05\u5355 26.5 \u5411 WebApplicationBuilder \u6dfb\u52a0\u7b2c\u4e09\u65b9\u65e5\u5fd7\u63d0\u4f9b\u7a0b\u5e8f<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args); \u2776\nbuilder.Logging.AddFile(); \u2777\n\nWebApplication app = builder.Build();\n\napp.MapGet(&quot;\/&quot;, () =&gt; &quot;Hello world!&quot;);\n\napp.Run();<\/code><\/pre>\n<p>\u2776 The WebApplicationBuilder configures the console and debug providers as normal.<br \/>\nWebApplicationBuilder \u7167\u5e38\u914d\u7f6e\u63a7\u5236\u53f0\u548c\u8c03\u8bd5\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<p>\u2777 Adds the new file logging provider to the logger factory<br \/>\n\u5c06\u65b0\u7684\u6587\u4ef6\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230 Logger \u5de5\u5382<\/p>\n<p><b>NOTE<\/b> Adding a new provider doesn\u2019t replace existing providers. WebApplicationBuilder automatically adds the console and debug logging providers in listing 26.5. To remove them, call builder.Logging.ClearProviders() before adding the file provider.<br \/>\n\u6ce8\u610f:\u6dfb\u52a0\u65b0\u7684\u63d0\u4f9b\u5546\u4e0d\u4f1a\u66ff\u6362\u73b0\u6709\u7684\u63d0\u4f9b\u5546\u3002WebApplicationBuilder \u5728\u6e05\u5355 26.5 \u4e2d\u81ea\u52a8\u6dfb\u52a0\u63a7\u5236\u53f0\u548c\u8c03\u8bd5\u65e5\u5fd7\u63d0\u4f9b\u7a0b\u5e8f\u3002\u8981\u5220\u9664\u5b83\u4eec\uff0c\u8bf7\u8c03\u7528 builder\u3002Logging.ClearProviders\uff08\uff09 \u7684\u8c03\u7528\u3002<\/p>\n<p>With the file logging provider configured, you can run the application and generate logs. Every time your application writes a log using an ILogger instance, ILogger writes the message to all configured providers, as shown in figure 26.7. The console messages are conveniently available, but you also have a persistent record of the logs stored in a file.<br \/>\n\u914d\u7f6e\u6587\u4ef6\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u540e\uff0c\u60a8\u53ef\u4ee5\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u5e76\u751f\u6210\u65e5\u5fd7\u3002\u6bcf\u6b21\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528 ILogger \u5b9e\u4f8b\u5199\u5165\u65e5\u5fd7\u65f6\uff0cILogger \u90fd\u4f1a\u5c06\u6d88\u606f\u5199\u5165\u6240\u6709\u914d\u7f6e\u7684\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u5982\u56fe 26.7 \u6240\u793a\u3002\u63a7\u5236\u53f0\u6d88\u606f\u975e\u5e38\u65b9\u4fbf\uff0c\u4f46\u60a8\u4e5f\u6709\u5b58\u50a8\u5728\u6587\u4ef6\u4e2d\u7684\u65e5\u5fd7\u7684\u6301\u4e45\u8bb0\u5f55\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2607.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 26.7 Logging a message with ILogger writes the log using all the configured providers. This lets you, for example, log a convenient message to the console while also persisting the logs to a file.<br \/>\n\u56fe 26.7 \u4f7f\u7528 ILogger \u8bb0\u5f55\u6d88\u606f\u4f1a\u4f7f\u7528\u6240\u6709\u914d\u7f6e\u7684\u63d0\u4f9b\u7a0b\u5e8f\u5199\u5165\u65e5\u5fd7\u3002\u4f8b\u5982\uff0c\u8fd9\u6837\uff0c\u60a8\u5c31\u53ef\u4ee5\u5c06\u65b9\u4fbf\u7684\u6d88\u606f\u8bb0\u5f55\u5230\u63a7\u5236\u53f0\uff0c\u540c\u65f6\u5c06\u65e5\u5fd7\u4fdd\u5b58\u5230\u6587\u4ef6\u4e2d\u3002<\/p>\n<p><b>TIP<\/b> By default, the rolling file provider writes logs to a subdirectory of your application. You can specify additional options such as filenames and file size limits using overloads of AddFile(). For production, I recommend using a more established logging provider, such as Serilog.<br \/>\n\u63d0\u793a:\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6eda\u52a8\u6587\u4ef6\u63d0\u4f9b\u7a0b\u5e8f\u5c06\u65e5\u5fd7\u5199\u5165\u5e94\u7528\u7a0b\u5e8f\u7684\u5b50\u76ee\u5f55\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 AddFile\uff08\uff09 \u7684\u91cd\u8f7d\u6307\u5b9a\u5176\u4ed6\u9009\u9879\uff0c\u4f8b\u5982\u6587\u4ef6\u540d\u548c\u6587\u4ef6\u5927\u5c0f\u9650\u5236\u3002\u5bf9\u4e8e\u751f\u4ea7\u73af\u5883\uff0c\u6211\u5efa\u8bae\u4f7f\u7528\u66f4\u6210\u719f\u7684\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u4f8b\u5982 Serilog\u3002<\/p>\n<p>The key takeaway from listing 26.5 is that the provider system makes it easy to integrate existing logging frameworks and providers with the ASP.NET Core logging abstractions. Whichever logging provider you choose to use in your application, the principles are the same: add a new logging provider to WebApplicationBuilder.Logging using extension methods like AddConsole(), or AddFile() in this case.<br \/>\n\u6e05\u5355 26.5 \u7684\u5173\u952e\u8981\u70b9\u662f\uff0cprovider \u7cfb\u7edf\u53ef\u4ee5\u8f7b\u677e\u5730\u5c06\u73b0\u6709\u7684\u65e5\u5fd7\u6846\u67b6\u548c\u63d0\u4f9b\u7a0b\u5e8f\u4e0e ASP.NET Core \u65e5\u5fd7\u62bd\u8c61\u96c6\u6210\u3002\u65e0\u8bba\u60a8\u9009\u62e9\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u4f7f\u7528\u54ea\u79cd\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u539f\u5219\u90fd\u662f\u76f8\u540c\u7684\uff1a\u4f7f\u7528AddConsole\uff08\uff09\u6216AddFile\uff08\uff09\u7b49\u6269\u5c55\u65b9\u6cd5\u5411WebApplicationBuilder.Logging\u6dfb\u52a0\u65b0\u7684\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<p>Logging your application messages to a file can be useful in some scenarios, and it\u2019s certainly better than logging to a nonexistent console window in production, but it may still not be the best option.<br \/>\n\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u5c06\u5e94\u7528\u7a0b\u5e8f\u6d88\u606f\u8bb0\u5f55\u5230\u6587\u4ef6\u4e2d\u53ef\u80fd\u5f88\u6709\u7528\uff0c\u8fd9\u80af\u5b9a\u6bd4\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u8bb0\u5f55\u5230\u4e0d\u5b58\u5728\u7684\u63a7\u5236\u53f0\u7a97\u53e3\u8981\u597d\uff0c\u4f46\u5b83\u53ef\u80fd\u4ecd\u7136\u4e0d\u662f\u6700\u4f73\u9009\u62e9\u3002<\/p>\n<p>If you discovered a bug in production and needed to look at the logs quickly to see what happened, for example, you\u2019d need to log on to the remote server, find the log files on disk, and trawl through them to find the problem. If you have multiple web servers, you\u2019d have a mammoth job to fetch all the logs before you could even start to tackle the bug\u2014assuming that you even have remote access to the production servers! Not fun. Add to that the possibility of file permission or drive space problems, and file logging seems less attractive.<br \/>\n\u4f8b\u5982\uff0c\u5982\u679c\u60a8\u5728\u751f\u4ea7\u4e2d\u53d1\u73b0\u4e86\u4e00\u4e2a\u9519\u8bef\uff0c\u5e76\u4e14\u9700\u8981\u5feb\u901f\u67e5\u770b\u65e5\u5fd7\u4ee5\u4e86\u89e3\u53d1\u751f\u4e86\u4ec0\u4e48\uff0c\u5219\u9700\u8981\u767b\u5f55\u5230\u8fdc\u7a0b\u670d\u52a1\u5668\uff0c\u5728\u78c1\u76d8\u4e0a\u627e\u5230\u65e5\u5fd7\u6587\u4ef6\uff0c\u7136\u540e\u6d4f\u89c8\u5b83\u4eec\u4ee5\u67e5\u627e\u95ee\u9898\u3002\u5982\u679c\u60a8\u6709\u591a\u4e2a Web \u670d\u52a1\u5668\uff0c\u90a3\u4e48\u60a8\u5c06\u9762\u4e34\u4e00\u9879\u8270\u5de8\u7684\u5de5\u4f5c\u6765\u83b7\u53d6\u6240\u6709\u65e5\u5fd7\uff0c\u7136\u540e\u624d\u80fd\u5f00\u59cb\u5904\u7406\u9519\u8bef \u2014 \u5047\u8bbe\u60a8\u751a\u81f3\u53ef\u4ee5\u8fdc\u7a0b\u8bbf\u95ee\u751f\u4ea7\u670d\u52a1\u5668\uff01\u4e0d\u597d\u73a9\u3002\u518d\u52a0\u4e0a\u6587\u4ef6\u6743\u9650\u6216\u9a71\u52a8\u5668\u7a7a\u95f4\u95ee\u9898\u7684\u53ef\u80fd\u6027\uff0c\u6587\u4ef6\u65e5\u5fd7\u8bb0\u5f55\u4f3c\u4e4e\u4e0d\u90a3\u4e48\u6709\u5438\u5f15\u529b\u3002<\/p>\n<p>Instead, it\u2019s often better to send your logs to a centralized location, separate from your application. Exactly where this location may be is up to you; the key is that each instance of your app sends its logs to the same location, separate from the app itself.<br \/>\n\u76f8\u53cd\uff0c\u901a\u5e38\u6700\u597d\u5c06\u65e5\u5fd7\u53d1\u9001\u5230\u4e0e\u5e94\u7528\u7a0b\u5e8f\u5206\u5f00\u7684\u96c6\u4e2d\u4f4d\u7f6e\u3002\u8fd9\u4e2a\u4f4d\u7f6e\u7684\u786e\u5207\u4f4d\u7f6e\u53d6\u51b3\u4e8e\u60a8;\u5173\u952e\u662f\u5e94\u7528\u7a0b\u5e8f\u7684\u6bcf\u4e2a\u5b9e\u4f8b\u90fd\u5c06\u5176\u65e5\u5fd7\u53d1\u9001\u5230\u540c\u4e00\u4f4d\u7f6e\uff0c\u4e0e\u5e94\u7528\u7a0b\u5e8f\u672c\u8eab\u5206\u5f00\u3002<\/p>\n<p>If you\u2019re running your app on Microsoft Azure, you get centralized logging for free because you can collect logs using the Azure App Service provider. Alternatively, you could send your logs to a third-party log aggregator service such as elmah.io (<a href=\"https:\/\/elmah.io\">https:\/\/elmah.io<\/a>) or Seq (<a href=\"https:\/\/getseq.net\">https:\/\/getseq.net<\/a>). You can find ASP.NET Core logging providers for each of these services on NuGet, so adding them is the same process as adding the file provider you\u2019ve seen already.<br \/>\n\u5982\u679c\u60a8\u5728 Microsoft Azure \u4e0a\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\uff0c\u5219\u53ef\u4ee5\u514d\u8d39\u83b7\u5f97\u96c6\u4e2d\u5f0f\u65e5\u5fd7\u8bb0\u5f55\uff0c\u56e0\u4e3a\u60a8\u53ef\u4ee5\u4f7f\u7528 Azure \u5e94\u7528\u7a0b\u5e8f\u670d\u52a1\u63d0\u4f9b\u5546\u6536\u96c6\u65e5\u5fd7\u3002\u6216\u8005\uff0c\u60a8\u4e5f\u53ef\u4ee5\u5c06\u65e5\u5fd7\u53d1\u9001\u5230\u7b2c\u4e09\u65b9\u65e5\u5fd7\u805a\u5408\u5668\u670d\u52a1\uff0c\u4f8b\u5982 elmah.io \uff08<a href=\"https:\/\/elmah.io\">https:\/\/elmah.io<\/a>\uff09 \u6216 Seq \uff08<a href=\"https:\/\/getseq.net\uff09\u3002\u53ef\u4ee5\u5728\">https:\/\/getseq.net\uff09\u3002\u53ef\u4ee5\u5728<\/a> NuGet \u4e0a\u627e\u5230\u6bcf\u4e2a\u670d\u52a1\u7684 ASP.NET Core \u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u56e0\u6b64\u6dfb\u52a0\u5b83\u4eec\u7684\u8fc7\u7a0b\u4e0e\u6dfb\u52a0\u5df2\u770b\u5230\u7684\u6587\u4ef6\u63d0\u4f9b\u7a0b\u5e8f\u7684\u8fc7\u7a0b\u76f8\u540c\u3002<\/p>\n<p>Whichever providers you add, once you start running your apps in production, you\u2019ll quickly discover a new problem: the sheer number of log messages your app generates! In the next section you\u2019ll learn how to keep this under control without affecting your local development.<br \/>\n\u65e0\u8bba\u60a8\u6dfb\u52a0\u54ea\u4e2a\u63d0\u4f9b\u5546\uff0c\u4e00\u65e6\u60a8\u5f00\u59cb\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\uff0c\u60a8\u5f88\u5feb\u5c31\u4f1a\u53d1\u73b0\u4e00\u4e2a\u65b0\u95ee\u9898\uff1a\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u751f\u6210\u7684\u65e5\u5fd7\u6d88\u606f\u6570\u91cf\u5e9e\u5927\uff01\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u5728\u4e0d\u5f71\u54cd\u672c\u5730\u5f00\u53d1\u7684\u60c5\u51b5\u4e0b\u63a7\u5236\u8fd9\u79cd\u60c5\u51b5\u3002<\/p>\n<h2>26.4 Changing log verbosity with filtering<\/h2>\n<p>26.4 \u901a\u8fc7\u8fc7\u6ee4\u66f4\u6539\u65e5\u5fd7\u8be6\u7ec6\u7a0b\u5ea6<\/p>\n<p>In this section you\u2019ll see how to reduce the number of log messages written to the logger providers. You\u2019ll learn how to apply a base level filter, filter out messages from specific namespaces, and use logging provider-specific filters.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u51cf\u5c11\u5199\u5165 Logger \u63d0\u4f9b\u7a0b\u5e8f\u7684\u65e5\u5fd7\u6d88\u606f\u6570\u91cf\u3002\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u5e94\u7528\u57fa\u672c\u7ea7\u522b\u7684\u8fc7\u6ee4\u5668\u3001\u8fc7\u6ee4\u6389\u6765\u81ea\u7279\u5b9a\u547d\u540d\u7a7a\u95f4\u7684\u6d88\u606f\u4ee5\u53ca\u4f7f\u7528\u7279\u5b9a\u4e8e\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u5546\u7684\u8fc7\u6ee4\u5668\u3002<\/p>\n<p>If you\u2019ve been playing around with the logging samples, you\u2019ll probably have noticed that you get a lot of log messages, even for a single request like the one in figure 26.2: messages from the Kestrel server and messages from EF Core, not to mention your own custom messages. When you\u2019re debugging locally, having access to all that detailed information is extremely useful, but in production you\u2019ll be so swamped by noise that picking out the important messages will be difficult.<br \/>\n\u5982\u679c\u60a8\u4e00\u76f4\u5728\u4f7f\u7528\u65e5\u5fd7\u8bb0\u5f55\u793a\u4f8b\uff0c\u5219\u53ef\u80fd\u5df2\u7ecf\u6ce8\u610f\u5230\uff0c\u5373\u4f7f\u5bf9\u4e8e\u5982\u56fe 26.2 \u6240\u793a\u7684\u5355\u4e2a\u8bf7\u6c42\uff1a\u6765\u81ea Kestrel \u670d\u52a1\u5668\u7684\u6d88\u606f\u548c\u6765\u81ea EF Core \u7684\u6d88\u606f\uff0c\u60a8\u4e5f\u4f1a\u6536\u5230\u5927\u91cf\u65e5\u5fd7\u6d88\u606f\uff0c\u66f4\u4e0d\u7528\u8bf4\u60a8\u81ea\u5df1\u7684\u81ea\u5b9a\u4e49\u6d88\u606f\u4e86\u3002\u5728\u672c\u5730\u8c03\u8bd5\u65f6\uff0c\u8bbf\u95ee\u6240\u6709\u8fd9\u4e9b\u8be6\u7ec6\u4fe1\u606f\u975e\u5e38\u6709\u7528\uff0c\u4f46\u5728\u751f\u4ea7\u73af\u5883\u4e2d\uff0c\u60a8\u5c06\u88ab\u566a\u97f3\u6240\u6df9\u6ca1\uff0c\u4ee5\u81f3\u4e8e\u5f88\u96be\u6311\u9009\u51fa\u91cd\u8981\u7684\u6d88\u606f\u3002<\/p>\n<p>ASP.NET Core includes the ability to filter out log messages before they\u2019re written, based on a combination of three things:<br \/>\nASP.NET Core \u5305\u62ec\u5728\u5199\u5165\u65e5\u5fd7\u6d88\u606f\u4e4b\u524d\u6839\u636e\u4ee5\u4e0b\u4e09\u9879\u7ec4\u5408\u7b5b\u9009\u51fa\u65e5\u5fd7\u6d88\u606f\u7684\u529f\u80fd\uff1a<\/p>\n<p>\u2022  The log level of the message<br \/>\n\u6d88\u606f\u7684\u65e5\u5fd7\u7ea7\u522b<\/p>\n<p>\u2022  The category of the logger (who created the log)<br \/>\n\u8bb0\u5f55\u5668\u7684\u7c7b\u522b\uff08\u521b\u5efa\u65e5\u5fd7\u7684\u4eba\uff09<\/p>\n<p>\u2022  The logger provider (where the log will be written)<br \/>\n\u8bb0\u5f55\u5668\u63d0\u4f9b\u7a0b\u5e8f\uff08\u5c06\u5199\u5165\u65e5\u5fd7\u7684\u4f4d\u7f6e\uff09<\/p>\n<p>You can create multiple rules using these properties, and for each log that\u2019s created, the most specific rule is applied to determine whether the log should be written to the output. You could create the following three rules:<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e9b\u5c5e\u6027\u521b\u5efa\u591a\u4e2a\u89c4\u5219\uff0c\u5bf9\u4e8e\u521b\u5efa\u7684\u6bcf\u4e2a\u65e5\u5fd7\uff0c\u5c06\u5e94\u7528\u6700\u5177\u4f53\u7684\u89c4\u5219\u6765\u786e\u5b9a\u662f\u5426\u5e94\u5c06\u65e5\u5fd7\u5199\u5165\u8f93\u51fa\u3002\u60a8\u53ef\u4ee5\u521b\u5efa\u4ee5\u4e0b\u4e09\u6761\u89c4\u5219\uff1a<\/p>\n<p>\u2022  The default minimum log level is Information. If no other rules apply, only logs with a log level of Information or above will be written to providers.<br \/>\n\u9ed8\u8ba4\u7684\u6700\u5c0f\u65e5\u5fd7\u7ea7\u522b\u4e3a Information\u3002\u5982\u679c\u6ca1\u6709\u5176\u4ed6\u89c4\u5219\u9002\u7528\uff0c\u5219\u53ea\u4f1a\u5c06\u65e5\u5fd7\u7ea7\u522b\u4e3a Information \u6216\u66f4\u9ad8\u7684\u65e5\u5fd7\u5199\u5165\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<p>\u2022  For categories that start with Microsoft, the minimum log level is Warning. Any logger created in a namespace that starts with Microsoft will write only logs that have a log level of Warning or above. This would filter out the noisy framework messages you saw in figure 26.6.<br \/>\n\u5bf9\u4e8e\u4ee5 Microsoft \u5f00\u5934\u7684\u7c7b\u522b\uff0c\u6700\u4f4e\u65e5\u5fd7\u7ea7\u522b\u4e3a\u201c\u8b66\u544a\u201d\u3002\u5728\u4ee5 Microsoft \u5f00\u5934\u7684\u547d\u540d\u7a7a\u95f4\u4e2d\u521b\u5efa\u7684\u4efb\u4f55 Logger \u90fd\u5c06\u4ec5\u5199\u5165\u65e5\u5fd7\u7ea7\u522b\u4e3a Warning \u6216\u66f4\u9ad8\u7684\u65e5\u5fd7\u3002\u8fd9\u5c06\u8fc7\u6ee4\u6389\u4f60\u5728\u56fe 26.6 \u4e2d\u770b\u5230\u7684\u5608\u6742\u7684\u6846\u67b6\u6d88\u606f\u3002<\/p>\n<p>\u2022  For the console provider, the minimum log level is Error. Logs written to the console provider must have a minimum log level of Error. Logs with a lower level won\u2019t be written to the console, though they might be written using other providers.<br \/>\n\u5bf9\u4e8e\u63a7\u5236\u53f0\u63d0\u4f9b\u5546\uff0c\u6700\u4f4e\u65e5\u5fd7\u7ea7\u522b\u4e3a Error\u3002\u5199\u5165\u63a7\u5236\u53f0\u63d0\u4f9b\u7a0b\u5e8f\u7684\u65e5\u5fd7\u5fc5\u987b\u5177\u6709 Error \uff08\u9519\u8bef\uff09 \u7684\u6700\u4f4e\u65e5\u5fd7\u7ea7\u522b\u3002\u5177\u6709\u8f83\u4f4e\u7ea7\u522b\u7684\u65e5\u5fd7\u4e0d\u4f1a\u5199\u5165\u63a7\u5236\u53f0\uff0c\u5c3d\u7ba1\u5b83\u4eec\u53ef\u80fd\u662f\u4f7f\u7528\u5176\u4ed6\u63d0\u4f9b\u7a0b\u5e8f\u5199\u5165\u7684\u3002<\/p>\n<p>Typically, the goal with log filtering is to reduce the number of logs written to certain providers or from certain namespaces (based on the log category). Figure 26.8 shows a possible set of filtering rules that apply to the console and file logging providers.<br \/>\n\u901a\u5e38\uff0c\u65e5\u5fd7\u7b5b\u9009\u7684\u76ee\u6807\u662f\u51cf\u5c11\u5199\u5165\u67d0\u4e9b\u63d0\u4f9b\u7a0b\u5e8f\u6216\u67d0\u4e9b\u547d\u540d\u7a7a\u95f4\uff08\u57fa\u4e8e\u65e5\u5fd7\u7c7b\u522b\uff09\u7684\u65e5\u5fd7\u6570\u91cf\u3002\u56fe 26.8 \u663e\u793a\u4e86\u4e00\u7ec4\u53ef\u80fd\u7684\u8fc7\u6ee4\u89c4\u5219\uff0c\u8fd9\u4e9b\u89c4\u5219\u9002\u7528\u4e8e\u63a7\u5236\u53f0\u548c\u6587\u4ef6\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2608.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 26.8 Applying filtering rules to a log message to determine whether a log should be written. For each provider, the most specific rule is selected. If the log exceeds the rule\u2019s required minimum level, the provider writes the log; otherwise, it discards it.<br \/>\n\u56fe 26.8 \u5c06\u8fc7\u6ee4\u89c4\u5219\u5e94\u7528\u4e8e\u65e5\u5fd7\u6d88\u606f\u4ee5\u786e\u5b9a\u662f\u5426\u5e94\u5199\u5165\u65e5\u5fd7\u3002\u5bf9\u4e8e\u6bcf\u4e2a\u63d0\u4f9b\u5546\uff0c\u5c06\u9009\u62e9\u6700\u5177\u4f53\u7684\u89c4\u5219\u3002\u5982\u679c\u65e5\u5fd7\u8d85\u8fc7\u89c4\u5219\u6240\u9700\u7684\u6700\u4f4e\u7ea7\u522b\uff0c\u5219\u63d0\u4f9b\u7a0b\u5e8f\u5c06\u5199\u5165\u65e5\u5fd7;\u5426\u5219\uff0c\u5b83\u5c06\u4e22\u5f03\u5b83\u3002<\/p>\n<p>In this example, the console logger explicitly restricts logs written in the Microsoft namespace to Warning or above, so the console logger ignores the log message shown. Conversely, the file logger doesn\u2019t have a rule that explicitly restricts the Microsoft namespace, so it uses the configured minimum level of Information and writes the log to the output.<br \/>\n\u5728\u6b64\u793a\u4f8b\u4e2d\uff0c\u63a7\u5236\u53f0\u8bb0\u5f55\u5668\u660e\u786e\u5c06 Microsoft \u547d\u540d\u7a7a\u95f4\u4e2d\u5199\u5165\u7684\u65e5\u5fd7\u9650\u5236\u4e3a Warning \u6216\u66f4\u9ad8\u7ea7\u522b\uff0c\u56e0\u6b64\u63a7\u5236\u53f0\u8bb0\u5f55\u5668\u4f1a\u5ffd\u7565\u663e\u793a\u7684\u65e5\u5fd7\u6d88\u606f\u3002\u76f8\u53cd\uff0c\u6587\u4ef6\u8bb0\u5f55\u5668\u6ca1\u6709\u660e\u786e\u9650\u5236 Microsoft \u547d\u540d\u7a7a\u95f4\u7684\u89c4\u5219\uff0c\u56e0\u6b64\u5b83\u4f7f\u7528\u914d\u7f6e\u7684\u6700\u4f4e\u7ea7\u522b Information \u5e76\u5c06\u65e5\u5fd7\u5199\u5165\u8f93\u51fa\u3002<\/p>\n<p><b>TIP<\/b> Only a single rule is chosen when deciding whether a log message should be written; rules aren\u2019t combined. In figure 26.8, rule 1 is considered to be more specific than rule 5, so the log is written to the file provider, even though technically, both rules could apply.<br \/>\n\u63d0\u793a:\u5728\u51b3\u5b9a\u662f\u5426\u5e94\u5199\u5165\u65e5\u5fd7\u6d88\u606f\u65f6\uff0c\u53ea\u9009\u62e9\u4e00\u4e2a\u89c4\u5219;\u89c4\u5219\u4e0d\u4f1a\u5408\u5e76\u3002\u5728\u56fe 26.8 \u4e2d\uff0c\u89c4\u5219 1 \u88ab\u8ba4\u4e3a\u6bd4\u89c4\u5219 5 \u66f4\u5177\u4f53\uff0c\u56e0\u6b64\u65e5\u5fd7\u88ab\u5199\u5165\u6587\u4ef6\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u5373\u4f7f\u4ece\u6280\u672f\u4e0a\u8bb2\uff0c\u8fd9\u4e24\u4e2a\u89c4\u5219\u90fd\u9002\u7528\u3002<\/p>\n<p>You typically define your app\u2019s set of logging rules using the layered configuration approach discussed in chapter 10, because this lets you easily have different rules when running in development and production.<br \/>\n\u60a8\u901a\u5e38\u4f7f\u7528\u7b2c 10 \u7ae0\u4e2d\u8ba8\u8bba\u7684\u5206\u5c42\u914d\u7f6e\u65b9\u6cd5\u6765\u5b9a\u4e49\u5e94\u7528\u7a0b\u5e8f\u7684\u65e5\u5fd7\u8bb0\u5f55\u89c4\u5219\u96c6\uff0c\u56e0\u4e3a\u8fd9\u53ef\u4ee5\u8ba9\u60a8\u5728\u5f00\u53d1\u548c\u751f\u4ea7\u73af\u5883\u4e2d\u8fd0\u884c\u65f6\u8f7b\u677e\u62e5\u6709\u4e0d\u540c\u7684\u89c4\u5219\u3002<\/p>\n<p><b>TIP<\/b> As you saw in chapter 11, you can load configuration settings from multiple sources, like JSON files and environment variables, and can load them conditionally based on the IHostingEnvironment. A common practice is to include logging settings for your production environment in appsettings.json and overrides for your local development environment in appsettings.Development.json.<br \/>\n\u63d0\u793a:\u6b63\u5982\u60a8\u5728\u7b2c 11 \u7ae0\u4e2d\u6240\u770b\u5230\u7684\uff0c\u60a8\u53ef\u4ee5\u4ece\u591a\u4e2a\u6e90\uff08\u5982 JSON \u6587\u4ef6\u548c\u73af\u5883\u53d8\u91cf\uff09\u52a0\u8f7d\u914d\u7f6e\u8bbe\u7f6e\uff0c\u5e76\u4e14\u53ef\u4ee5\u57fa\u4e8e IHostingEnvironment \u6709\u6761\u4ef6\u5730\u52a0\u8f7d\u5b83\u4eec\u3002\u4e00\u79cd\u5e38\u89c1\u7684\u505a\u6cd5\u662f\u5728 appsettings.json \u4e2d\u5305\u542b\u751f\u4ea7\u73af\u5883\u7684\u65e5\u5fd7\u8bb0\u5f55\u8bbe\u7f6e\uff0c\u5e76\u5728 appsettings \u4e2d\u5305\u542b\u672c\u5730\u5f00\u53d1\u73af\u5883\u7684\u8986\u76d6\u3002Development.json\u3002<\/p>\n<p>WebApplicationBuilder automatically loads configuration rules from the &quot;Logging&quot; section of the IConfiguration object. This happens automatically, and you rarely need to customize it, but listing 26.6 shows how you could also add configuration rules from the &quot;LoggingRules&quot; section using AddConfiguration().<br \/>\nWebApplicationBuilder \u4f1a\u81ea\u52a8\u4ece IConfiguration \u5bf9\u8c61\u7684 \u201cLogging\u201d \u90e8\u5206\u52a0\u8f7d\u914d\u7f6e\u89c4\u5219\u3002\u8fd9\u662f\u81ea\u52a8\u53d1\u751f\u7684\uff0c\u60a8\u5f88\u5c11\u9700\u8981\u81ea\u5b9a\u4e49\u5b83\uff0c\u4f46\u662f\u6e05\u5355 26.6 \u663e\u793a\u4e86\u5982\u4f55\u4f7f\u7528 AddConfiguration\uff08\uff09 \u4ece \u201cLoggingRules\u201d \u90e8\u5206\u6dfb\u52a0\u914d\u7f6e\u89c4\u5219\u3002<\/p>\n<p><b>NOTE<\/b> WebApplicationBuilder always adds the configuration to load from the &quot;Logging&quot; section; you can\u2019t remove this. For this reason, it\u2019s rarely worth adding configuration yourself; instead, use the default &quot;Logging&quot; configuration section where possible.<br \/>\n\u6ce8\u610f:WebApplicationBuilder \u59cb\u7ec8\u4ece \u201cLogging\u201d \u90e8\u5206\u6dfb\u52a0\u8981\u52a0\u8f7d\u7684\u914d\u7f6e;\u60a8\u65e0\u6cd5\u5220\u9664\u6b64\u5185\u5bb9\u3002\u56e0\u6b64\uff0c\u60a8\u81ea\u5df1\u6dfb\u52a0\u914d\u7f6e\u5f88\u5c11\u503c\u5f97;\u76f8\u53cd\uff0c\u8bf7\u5c3d\u53ef\u80fd\u4f7f\u7528\u9ed8\u8ba4\u7684 \u201cLogging\u201d \u914d\u7f6e\u90e8\u5206\u3002<\/p>\n<p>Listing 26.6 Loading logging configuration using AddConfiguration()<br \/>\n\u5217\u8868 26.6 \u4f7f\u7528 AddConfiguration\uff08\uff09 \u52a0\u8f7d\u65e5\u5fd7\u914d\u7f6e<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\nbuilder.Logging.AddConfiguration(\n    builder.Configuration.GetSection(&quot;LoggingRules&quot;)); \u2776\n\nvar app = builder.Build();\n\napp.MapGet(&quot;\/&quot;, () =&gt; &quot;Hello world!&quot;);\napp.Run();<\/code><\/pre>\n<p>\u2776 Loads the log filtering configuration from the LoggingRules section<br \/>\n\u4ece LoggingRules \u90e8\u5206\u52a0\u8f7d\u65e5\u5fd7\u8fc7\u6ee4\u914d\u7f6e<\/p>\n<p>Assuming that you don\u2019t override the configuration section, your appsettings.json will typically contain a &quot;Logging&quot; section, which defines the configuration rules for your app. Listing 26.8 shows how this might look to define all the rules shown in figure 26.8.<br \/>\n\u5047\u8bbe\u4f60\u6ca1\u6709\u8986\u76d6 configuration \u90e8\u5206\uff0c\u4f60\u7684 appsettings.json \u901a\u5e38\u4f1a\u5305\u542b\u4e00\u4e2a \u201cLogging\u201d \u90e8\u5206\uff0c\u5b83\u5b9a\u4e49\u4e86\u4f60\u7684\u5e94\u7528\u7a0b\u5e8f\u7684\u914d\u7f6e\u89c4\u5219\u3002\u6e05\u5355 26.8 \u663e\u793a\u4e86\u5982\u4f55\u5b9a\u4e49\u56fe 26.8 \u4e2d\u6240\u793a\u7684\u6240\u6709\u89c4\u5219\u3002<\/p>\n<p>Listing 26.7 The log filtering configuration section of appsettings.json<br \/>\n\u6e05\u5355 26.7 appsettings.json \u7684\u65e5\u5fd7\u8fc7\u6ee4\u914d\u7f6e\u90e8\u5206<\/p>\n<pre><code>{\n  &quot;Logging&quot;: {\n    &quot;LogLevel&quot;: {             #A\n      &quot;Default&quot;: &quot;Debug&quot;,     #A\n      &quot;System&quot;: &quot;Warning&quot;,    #A\n      &quot;Microsoft&quot;: &quot;Warning&quot;  #A\n    },\n    &quot;File&quot;: {                      #B\n      &quot;LogLevel&quot;: {                #B\n        &quot;Default&quot;: &quot;Information&quot;   #B\n      }\n    },\n    &quot;Console&quot;: {                 #C\n      &quot;LogLevel&quot;: {              #C\n        &quot;Default&quot;: &quot;Debug&quot;,      #C\n        &quot;Microsoft&quot;: &quot;Warning&quot;   #C\n      }\n    }\n  }\n}<\/code><\/pre>\n<p>\u2776 Rules to apply if there are no specific rules for a provider<br \/>\n\u5982\u679c\u63d0\u4f9b\u7a0b\u5e8f\u6ca1\u6709\u7279\u5b9a\u89c4\u5219\uff0c\u5219\u8981\u5e94\u7528\u7684\u89c4\u5219 <\/p>\n<p>\u2777 Rules to apply to the File provider<br \/>\n\u5e94\u7528\u4e8e\u6587\u4ef6\u63d0\u4f9b\u7a0b\u5e8f\u7684\u89c4\u5219<\/p>\n<p>\u2778 Rules to apply to the Console provider<br \/>\n\u5e94\u7528\u4e8e\u63a7\u5236\u53f0\u63d0\u4f9b\u7a0b\u5e8f\u7684\u89c4\u5219<\/p>\n<p>When creating your logging rules, the important thing to bear in mind is that if you have any provider-specific rules, these will take precedence over the category-based rules defined in the &quot;LogLevel&quot; section. Therefore, for the configuration defined in listing 26.7, if your app uses only the file or console logging providers, the rules in the &quot;LogLevel&quot; section will effectively never apply.<br \/>\n\u5728\u521b\u5efa\u65e5\u5fd7\u8bb0\u5f55\u89c4\u5219\u65f6\uff0c\u8981\u8bb0\u4f4f\u7684\u91cd\u8981\u4e00\u70b9\u662f\uff0c\u5982\u679c\u60a8\u6709\u4efb\u4f55\u7279\u5b9a\u4e8e\u63d0\u4f9b\u7a0b\u5e8f\u7684\u89c4\u5219\uff0c\u8fd9\u4e9b\u89c4\u5219\u5c06\u4f18\u5148\u4e8e \u201cLogLevel\u201d \u90e8\u5206\u4e2d\u5b9a\u4e49\u7684\u57fa\u4e8e\u7c7b\u522b\u7684\u89c4\u5219\u3002\u56e0\u6b64\uff0c\u5bf9\u4e8e\u6e05\u5355 26.7 \u4e2d\u5b9a\u4e49\u7684\u914d\u7f6e\uff0c\u5982\u679c\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4ec5\u4f7f\u7528\u6587\u4ef6\u6216\u63a7\u5236\u53f0\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u5219\u201cLogLevel\u201d\u90e8\u5206\u4e2d\u7684\u89c4\u5219\u5b9e\u9645\u4e0a\u5c06\u6c38\u8fdc\u4e0d\u4f1a\u9002\u7528\u3002<\/p>\n<p>If you find this confusing, don\u2019t worry; so do I. Whenever I\u2019m setting up logging, I check the algorithm used to determine which rule applies for a given provider and category, which is as follows:<br \/>\n\u5982\u679c\u60a8\u89c9\u5f97\u8fd9\u4ee4\u4eba\u56f0\u60d1\uff0c\u8bf7\u4e0d\u8981\u62c5\u5fc3;\u6211\u4e5f\u662f\u3002\u6bcf\u5f53\u6211\u8bbe\u7f6e\u65e5\u5fd7\u8bb0\u5f55\u65f6\uff0c\u6211\u90fd\u4f1a\u68c0\u67e5\u7528\u4e8e\u786e\u5b9a\u54ea\u4e2a\u89c4\u5219\u9002\u7528\u4e8e\u7ed9\u5b9a\u63d0\u4f9b\u7a0b\u5e8f\u548c\u7c7b\u522b\u7684\u7b97\u6cd5\uff0c\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<ol>\n<li>\n<p>Select all rules for the given provider. If no rules apply, select all rules that don\u2019t define a provider (the top &quot;LogLevel&quot; section from listing 26.7).<br \/>\n\u9009\u62e9\u7ed9\u5b9a\u63d0\u4f9b\u7a0b\u5e8f\u7684\u6240\u6709\u89c4\u5219\u3002\u5982\u679c\u6ca1\u6709\u9002\u7528\u7684\u89c4\u5219\uff0c\u8bf7\u9009\u62e9\u6240\u6709\u672a\u5b9a\u4e49\u63d0\u4f9b\u7a0b\u5e8f\u7684\u89c4\u5219\uff08\u6e05\u5355 26.7 \u4e2d\u7684\u9876\u90e8\u201cLogLevel\u201d\u90e8\u5206\uff09\u3002<\/p>\n<\/li>\n<li>\n<p>From the selected rules, select rules with the longest matching category prefix. If no selected rules match the category prefix, select the &quot;Default&quot; if present.<br \/>\n\u4ece\u6240\u9009\u89c4\u5219\u4e2d\uff0c\u9009\u62e9\u5177\u6709\u6700\u957f\u5339\u914d\u7c7b\u522b\u524d\u7f00\u7684\u89c4\u5219\u3002\u5982\u679c\u6ca1\u6709\u9009\u5b9a\u7684\u89c4\u5219\u4e0e\u7c7b\u522b\u524d\u7f00\u5339\u914d\uff0c\u8bf7\u9009\u62e9\u201cDefault\u201d\uff08\u9ed8\u8ba4\uff09\uff08\u5982\u679c\u5b58\u5728\uff09\u3002<\/p>\n<\/li>\n<li>\n<p>If multiple rules are selected, use the last one.<br \/>\n\u5982\u679c\u9009\u62e9\u4e86\u591a\u4e2a\u89c4\u5219\uff0c\u8bf7\u4f7f\u7528\u6700\u540e\u4e00\u4e2a\u89c4\u5219\u3002<\/p>\n<\/li>\n<li>\n<p>If no rules are selected, use the global minimum level, &quot;LogLevel:Default&quot; (Debug in listing 26.7).<br \/>\n\u5982\u679c\u672a\u9009\u62e9\u4efb\u4f55\u89c4\u5219\uff0c\u8bf7\u4f7f\u7528\u5168\u5c40\u6700\u5c0f\u7ea7\u522b \u201cLogLevel\uff1aDefault\u201d \uff08\u5217\u8868 26.7 \u4e2d\u7684 Debug\uff09\u3002<\/p>\n<\/li>\n<\/ol>\n<p>Each of these steps except the last narrows down the applicable rules for a log message until you\u2019re left with a single rule. You saw this in effect for a &quot;Microsoft&quot; category log in figure 26.8. Figure 26.9 shows the process in more detail.<br \/>\n\u9664\u6700\u540e\u4e00\u4e2a\u6b65\u9aa4\u5916\uff0c\u8fd9\u4e9b\u6b65\u9aa4\u4e2d\u7684\u6bcf\u4e00\u4e2a\u6b65\u9aa4\u90fd\u4f1a\u7f29\u5c0f\u65e5\u5fd7\u6d88\u606f\u7684\u9002\u7528\u89c4\u5219\u8303\u56f4\uff0c\u76f4\u5230\u60a8\u53ea\u5269\u4e0b\u4e00\u6761\u89c4\u5219\u3002\u60a8\u5728\u56fe 26.8 \u4e2d\u770b\u5230\u4e86 \u201cMicrosoft\u201d \u7c7b\u522b\u65e5\u5fd7\u7684\u6548\u679c\u3002\u56fe 26.9 \u66f4\u8be6\u7ec6\u5730\u663e\u793a\u4e86\u8be5\u8fc7\u7a0b\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2609.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 26.9 Selecting a rule to apply from the available set for the console provider and an Information level log. Each step reduces the number of rules that apply until you\u2019re left with only one.<br \/>\n\u56fe 26.9 \u4ece\u63a7\u5236\u53f0\u63d0\u4f9b\u7a0b\u5e8f\u7684\u53ef\u7528\u96c6\u548c\u4fe1\u606f\u7ea7\u522b\u65e5\u5fd7\u4e2d\u9009\u62e9\u8981\u5e94\u7528\u7684\u89c4\u5219\u3002\u6bcf\u4e2a\u6b65\u9aa4\u90fd\u4f1a\u51cf\u5c11\u9002\u7528\u7684\u89c4\u5219\u6570\uff0c\u76f4\u5230\u53ea\u5269\u4e0b\u4e00\u4e2a\u89c4\u5219\u3002<\/p>\n<p><b>WARNING<\/b> Log filtering rules aren\u2019t merged; a single rule is selected. Including provider-specific rules will override global category-specific rules, so I tend to stick to category-specific rules where possible to make the overall set of rules easier to understand.<br \/>\n\u8b66\u544a:\u65e5\u5fd7\u7b5b\u9009\u89c4\u5219\u4e0d\u4f1a\u5408\u5e76;\u5c06\u9009\u62e9\u5355\u4e2a\u89c4\u5219\u3002\u5305\u542b\u7279\u5b9a\u4e8e\u63d0\u4f9b\u5546\u7684\u89c4\u5219\u5c06\u8986\u76d6\u5168\u5c40\u7279\u5b9a\u4e8e\u7c7b\u522b\u7684\u89c4\u5219\uff0c\u56e0\u6b64\u6211\u503e\u5411\u4e8e\u5c3d\u53ef\u80fd\u575a\u6301\u4f7f\u7528\u7279\u5b9a\u4e8e\u7c7b\u522b\u7684\u89c4\u5219\uff0c\u4ee5\u4f7f\u6574\u4e2a\u89c4\u5219\u96c6\u66f4\u6613\u4e8e\u7406\u89e3\u3002<\/p>\n<p>With some effective filtering in place, your production logs should be much more manageable, as shown in figure 26.10. Generally, I find it\u2019s best to limit the logs from the ASP.NET Core infrastructure and referenced libraries to Warning or above while keeping logs that my app writes to Debug in development and Information in production.<br \/>\n\u901a\u8fc7\u4e00\u4e9b\u6709\u6548\u7684\u8fc7\u6ee4\uff0c\u60a8\u7684 \u751f\u4ea7\u65e5\u5fd7\u5e94\u8be5\u66f4\u6613\u4e8e\u7ba1\u7406\uff0c\u5982\u56fe 26.10 \u6240\u793a\u3002\u901a\u5e38\uff0c\u6211\u53d1\u73b0\u6700\u597d\u5c06\u6765\u81ea ASP.NET Core \u57fa\u7840\u8bbe\u65bd\u548c\u5f15\u7528\u5e93\u7684\u65e5\u5fd7\u9650\u5236\u4e3a Warning \u6216\u66f4\u9ad8\u7ea7\u522b\uff0c\u540c\u65f6\u4fdd\u7559\u6211\u7684\u5e94\u7528\u7a0b\u5e8f\u5199\u5165 Debug in development \u548c Information in production\u7684\u65e5\u5fd7\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2610.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 26.10 Using filtering to reduce the number of logs written. In this example, category filters have been added to the Microsoft and System namespaces, so only logs of Warning and above are recorded. That increases the proportion of logs that are directly relevant to your application.<br \/>\n\u56fe 26.10 \u4f7f\u7528\u8fc7\u6ee4\u6765\u51cf\u5c11\u5199\u5165\u7684\u65e5\u5fd7\u6570\u91cf\u3002\u5728\u6b64\u793a\u4f8b\u4e2d\uff0c\u7c7b\u522b\u7b5b\u9009\u5668\u5df2\u6dfb\u52a0\u5230 Microsoft \u548c System \u547d\u540d\u7a7a\u95f4\uff0c\u56e0\u6b64\u4ec5\u8bb0\u5f55 Warning \u53ca\u4ee5\u4e0a\u7684\u65e5\u5fd7\u3002\u8fd9\u4f1a\u589e\u52a0\u4e0e\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u76f4\u63a5\u76f8\u5173\u7684\u65e5\u5fd7\u7684\u6bd4\u4f8b\u3002<\/p>\n<p>This is close to the default configuration used in the ASP.NET Core templates. You may find you need to add additional category-specific filters, depending on which NuGet libraries you use and the categories they write to. The best way to find out is generally to run your app and see whether you get flooded with uninteresting log messages.<br \/>\n\u8fd9\u63a5\u8fd1 ASP.NET Core \u6a21\u677f\u4e2d\u4f7f\u7528\u7684\u9ed8\u8ba4\u914d\u7f6e\u3002\u4f60\u53ef\u80fd\u4f1a\u53d1\u73b0\u9700\u8981\u6dfb\u52a0\u5176\u4ed6\u7279\u5b9a\u4e8e\u7c7b\u522b\u7684\u7b5b\u9009\u5668\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u4f60\u4f7f\u7528\u7684 NuGet \u5e93\u4ee5\u53ca\u5b83\u4eec\u5199\u5165\u7684\u7c7b\u522b\u3002\u627e\u51fa\u7b54\u6848\u7684\u6700\u4f73\u65b9\u6cd5\u901a\u5e38\u662f\u8fd0\u884c\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u770b\u770b\u60a8\u662f\u5426\u88ab\u4e0d\u611f\u5174\u8da3\u7684\u65e5\u5fd7\u6d88\u606f\u6df9\u6ca1\u3002<\/p>\n<p><b>TIP<\/b> Most logging providers listen for configuration changes and update their filters dynamically. That means you should be able to modify your appsettings.json or appsettings.Development.json file and check the effect on the log messages, iterating quickly without restarting your app.<br \/>\n\u63d0\u793a:\u5927\u591a\u6570\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u4fa6\u542c\u914d\u7f6e\u66f4\u6539\u5e76\u52a8\u6001\u66f4\u65b0\u5176\u8fc7\u6ee4\u5668\u3002\u8fd9\u610f\u5473\u7740\u60a8\u5e94\u8be5\u80fd\u591f\u4fee\u6539 appsettings.json \u6216 appsettings\u3002Development.json\u6587\u4ef6\u5e76\u68c0\u67e5\u5bf9\u65e5\u5fd7\u6d88\u606f\u7684\u5f71\u54cd\uff0c\u5728\u4e0d\u91cd\u65b0\u542f\u52a8\u5e94\u7528\u7a0b\u5e8f\u7684\u60c5\u51b5\u4e0b\u5feb\u901f\u8fed\u4ee3\u3002<\/p>\n<p>Even with your log verbosity under control, if you stick to the default logging providers like the file or console loggers, you\u2019ll probably regret it in the long run. These log providers work perfectly well, but when it comes to finding specific error messages or analyzing your logs, you\u2019ll have your work cut out for you. In the next section you\u2019ll see how structured logging can help you tackle this problem.<br \/>\n\u5373\u4f7f\u4f60\u7684\u65e5\u5fd7\u8be6\u7ec6\u7a0b\u5ea6\u5f97\u5230\u63a7\u5236\uff0c\u5982\u679c\u4f60\u575a\u6301\u4f7f\u7528\u9ed8\u8ba4\u7684\u65e5\u5fd7\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u5982\u6587\u4ef6\u6216\u63a7\u5236\u53f0\u8bb0\u5f55\u5668\uff0c\u4ece\u957f\u8fdc\u6765\u770b\uff0c\u4f60\u53ef\u80fd\u4f1a\u540e\u6094\u3002\u8fd9\u4e9b\u65e5\u5fd7\u63d0\u4f9b\u7a0b\u5e8f\u8fd0\u884c\u826f\u597d\uff0c\u4f46\u662f\u5728\u67e5\u627e\u7279\u5b9a\u9519\u8bef\u6d88\u606f\u6216\u5206\u6790\u65e5\u5fd7\u65f6\uff0c\u60a8\u5c06\u9700\u8981\u5b8c\u6210\u5927\u91cf\u5de5\u4f5c\u3002\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u5982\u4f55\u5e2e\u52a9\u60a8\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u3002<\/p>\n<h2>26.5 Structured logging: Creating searchable, useful logs<\/h2>\n<p>26.5 \u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\uff1a\u521b\u5efa\u53ef\u641c\u7d22\u7684\u6709\u7528\u65e5\u5fd7<\/p>\n<p>In this section you\u2019ll learn how structured logging makes working with log messages easier. You\u2019ll learn to attach key-value pairs to log messages and how to store and query for key values using the structured logging provider Seq. Finally, you\u2019ll learn how to use scopes to attach key-value pairs to all log messages within a block.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u5982\u4f55\u66f4\u8f7b\u677e\u5730\u5904\u7406\u65e5\u5fd7\u6d88\u606f\u3002\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u5c06\u952e\u503c\u5bf9\u9644\u52a0\u5230\u65e5\u5fd7\u6d88\u606f\uff0c\u4ee5\u53ca\u5982\u4f55\u4f7f\u7528\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f Seq \u5b58\u50a8\u548c\u67e5\u8be2\u952e\u503c\u3002\u6700\u540e\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4f7f\u7528\u8303\u56f4\u5c06\u952e\u503c\u5bf9\u9644\u52a0\u5230\u5757\u4e2d\u7684\u6240\u6709\u65e5\u5fd7\u6d88\u606f\u3002<\/p>\n<p>Let\u2019s imagine you\u2019ve rolled out the recipe application we\u2019ve been working on to production. You\u2019ve added logging to the app so that you can keep track of any errors in your application, and you\u2019re storing the logs in a file.<br \/>\n\u5047\u8bbe\u60a8\u5df2\u7ecf\u5c06\u6211\u4eec\u4e00\u76f4\u5728\u5f00\u53d1\u7684\u914d\u65b9\u5e94\u7528\u7a0b\u5e8f\u63a8\u5e7f\u5230\u751f\u4ea7\u73af\u5883\u4e2d\u3002\u60a8\u5df2\u5c06\u65e5\u5fd7\u8bb0\u5f55\u6dfb\u52a0\u5230\u5e94\u7528\u7a0b\u5e8f\uff0c\u4ee5\u4fbf\u60a8\u53ef\u4ee5\u8ddf\u8e2a\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u4efb\u4f55\u9519\u8bef\uff0c\u5e76\u4e14\u60a8\u5c06\u65e5\u5fd7\u5b58\u50a8\u5728\u6587\u4ef6\u4e2d\u3002<\/p>\n<p>One day, a customer calls and says they can\u2019t view their recipe. Sure enough, when you look through the log messages, you a see a warning:<br \/>\n\u6709\u4e00\u5929\uff0c\u4e00\u4f4d\u5ba2\u6237\u6253\u7535\u8bdd\u8bf4\u4ed6\u4eec\u65e0\u6cd5\u67e5\u770b\u4ed6\u4eec\u7684\u914d\u65b9\u3002\u679c\u7136\uff0c\u5f53\u60a8\u67e5\u770b\u65e5\u5fd7\u6d88\u606f\u65f6\uff0c\u60a8\u4f1a\u770b\u5230\u4e00\u6761\u8b66\u544a\uff1a<\/p>\n<pre><code>warn: RecipeApplication.Pages.Recipes.ViewModel [12]\n      Could not find recipe with id 3245<\/code><\/pre>\n<p>This piques your interest. Why did this happen? Has it happened before for this customer? Has it happened before for this recipe? Has it happened for other recipes? Does it happen regularly?<br \/>\n\u8fd9\u6fc0\u8d77\u4e86\u60a8\u7684\u5174\u8da3\u3002\u4e3a\u4ec0\u4e48\u4f1a\u8fd9\u6837\uff1f\u6b64\u5ba2\u6237\u4ee5\u524d\u53d1\u751f\u8fc7\u5417\uff1f\u8fd9\u4e2a\u98df\u8c31\u4ee5\u524d\u53d1\u751f\u8fc7\u5417\uff1f\u5176\u4ed6\u98df\u8c31\u4e5f\u53d1\u751f\u8fc7\u5417\uff1f\u5b83\u7ecf\u5e38\u53d1\u751f\u5417\uff1f<\/p>\n<p>How would you go about answering these questions? Given that the logs are stored in a text file, you might start doing basic text searches in your editor of choice, looking for the phrase &quot;Could not find recipe with id&quot;. Depending on your notepad-fu skills, you could probably get a fair way in answering your questions, but it would likely be a laborious, error-prone, and painful process.<br \/>\n\u60a8\u5c06\u5982\u4f55\u56de\u7b54\u8fd9\u4e9b\u95ee\u9898\uff1f\u9274\u4e8e\u65e5\u5fd7\u5b58\u50a8\u5728\u6587\u672c\u6587\u4ef6\u4e2d\uff0c\u60a8\u53ef\u4ee5\u5f00\u59cb\u5728\u6240\u9009\u7f16\u8f91\u5668\u4e2d\u8fdb\u884c\u57fa\u672c\u6587\u672c\u641c\u7d22\uff0c\u67e5\u627e\u77ed\u8bed\u201cCould not find recipe with id\u201d\u3002\u6839\u636e\u4f60\u7684\u8bb0\u4e8b\u672c\u6280\u80fd\uff0c\u4f60\u53ef\u80fd\u4f1a\u5f97\u5230\u4e00\u4e2a\u516c\u5e73\u7684\u65b9\u5f0f\u6765\u56de\u7b54\u4f60\u7684\u95ee\u9898\uff0c\u4f46\u8fd9\u53ef\u80fd\u662f\u4e00\u4e2a\u8d39\u529b\u3001\u5bb9\u6613\u51fa\u9519\u548c\u75db\u82e6\u7684\u8fc7\u7a0b\u3002<\/p>\n<p>The limiting factor is that the logs are stored as unstructured text, so text processing is the only option available to you. A better approach is to store the logs in a structured format so that you can easily query the logs, filter them, and create analytics. Structured logs could be stored in any format, but these days they\u2019re typically represented as JSON. A structured version of the same recipe warning log might look something like this:<br \/>\n\u9650\u5236\u56e0\u7d20\u662f\u65e5\u5fd7\u5b58\u50a8\u4e3a\u975e\u7ed3\u6784\u5316\u6587\u672c\uff0c\u56e0\u6b64\u6587\u672c\u5904\u7406\u662f\u60a8\u552f\u4e00\u53ef\u7528\u7684\u9009\u9879\u3002\u66f4\u597d\u7684\u65b9\u6cd5\u662f\u4ee5\u7ed3\u6784\u5316\u683c\u5f0f\u5b58\u50a8\u65e5\u5fd7\uff0c\u4ee5\u4fbf\u60a8\u53ef\u4ee5\u8f7b\u677e\u67e5\u8be2\u65e5\u5fd7\u3001\u7b5b\u9009\u65e5\u5fd7\u5e76\u521b\u5efa\u5206\u6790\u3002\u7ed3\u6784\u5316\u65e5\u5fd7\u53ef\u4ee5\u4ee5\u4efb\u4f55\u683c\u5f0f\u5b58\u50a8\uff0c\u4f46\u73b0\u5728\u5b83\u4eec\u901a\u5e38\u8868\u793a\u4e3a JSON\u3002\u540c\u4e00\u914d\u65b9\u8b66\u544a\u65e5\u5fd7\u7684\u7ed3\u6784\u5316\u7248\u672c\u53ef\u80fd\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code>{\n  &quot;eventLevel&quot;: &quot;Warning&quot;,\n  &quot;category&quot;: &quot;RecipeApplication.Pages.Recipes.ViewModel&quot;,\n  &quot;eventId&quot;: &quot;12&quot;,\n  &quot;messageTemplate&quot;: &quot;Could not find recipe with {recipeId}&quot;,\n  &quot;message&quot;: &quot;Could not find recipe with id 3245&quot;,\n  &quot;recipeId&quot;: &quot;3245&quot;\n}<\/code><\/pre>\n<p>This structured log message contains all the same details as the unstructured version, but in a format that would easily let you search for specific log entries. It makes it simple to filter logs by their EventLevel or to show only those logs relating to a specific recipe ID.<br \/>\n\u6b64\u7ed3\u6784\u5316\u65e5\u5fd7\u6d88\u606f\u5305\u542b\u4e0e\u975e\u7ed3\u6784\u5316\u7248\u672c\u76f8\u540c\u7684\u6240\u6709\u8be6\u7ec6\u4fe1\u606f\uff0c\u4f46\u683c\u5f0f\u53ef\u8ba9\u60a8\u8f7b\u677e\u641c\u7d22\u7279\u5b9a\u65e5\u5fd7\u6761\u76ee\u3002\u5b83\u4f7f\u6309\u65e5\u5fd7\u7684 EventLevel \u7b5b\u9009\u65e5\u5fd7\u6216\u4ec5\u663e\u793a\u4e0e\u7279\u5b9a\u914d\u65b9 ID \u76f8\u5173\u7684\u65e5\u5fd7\u53d8\u5f97\u7b80\u5355\u3002<\/p>\n<p><b>NOTE<\/b> This is only an example of what a structured log could look like. The format used for the logs will vary depending on the logging provider used and could be anything. The main point is that properties of the log are available as key-value pairs.<br \/>\n\u6ce8\u610f:\u8fd9\u53ea\u662f\u7ed3\u6784\u5316\u65e5\u5fd7\u7684\u4e00\u4e2a\u793a\u4f8b\u3002\u7528\u4e8e\u65e5\u5fd7\u7684\u683c\u5f0f\u5c06\u6839\u636e\u6240\u4f7f\u7528\u7684\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u800c\u6709\u6240\u4e0d\u540c\uff0c\u53ef\u4ee5\u662f\u4efb\u4f55\u5185\u5bb9\u3002\u8981\u70b9\u662f\u65e5\u5fd7\u7684\u5c5e\u6027\u53ef\u7528\u4f5c\u952e\u503c\u5bf9\u3002<\/p>\n<p>Adding structured logging to your app requires a logging provider that can create and store structured logs. Elasticsearch is a popular general search and analytics engine that can be used to store and query your logs. One big advantage of using a central store such as Elasticsearch is the ability to aggregate the logs from all your apps in one place and analyze them together. You can add the Elasticsearch.Extensions.Logging provider to your app in the same way as you added the file sink in section 26.3.<br \/>\n\u5411\u5e94\u7528\u6dfb\u52a0\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u9700\u8981\u53ef\u4ee5\u521b\u5efa\u548c\u5b58\u50a8\u7ed3\u6784\u5316\u65e5\u5fd7\u7684\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u3002Elasticsearch \u662f\u4e00\u79cd\u6d41\u884c\u7684\u901a\u7528\u641c\u7d22\u548c\u5206\u6790\u5f15\u64ce\uff0c\u53ef\u7528\u4e8e\u5b58\u50a8\u548c\u67e5\u8be2\u60a8\u7684\u65e5\u5fd7\u3002\u4f7f\u7528 Elasticsearch \u7b49\u4e2d\u592e\u5b58\u50a8\u7684\u4e00\u5927\u4f18\u52bf\u662f\u80fd\u591f\u5c06\u6765\u81ea\u6240\u6709\u5e94\u7528\u7a0b\u5e8f\u7684\u65e5\u5fd7\u805a\u5408\u5230\u4e00\u4e2a\u4f4d\u7f6e\u5e76\u4e00\u8d77\u5206\u6790\u5b83\u4eec\u3002\u60a8\u53ef\u4ee5\u6309\u7167\u5728\u7b2c 26.3 \u8282\u4e2d\u6dfb\u52a0\u6587\u4ef6\u63a5\u6536\u5668\u7684\u76f8\u540c\u65b9\u5f0f\u5c06 Elasticsearch.Extensions.Logging \u63d0\u4f9b\u7a0b\u5e8f\u6dfb\u52a0\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u3002<\/p>\n<p><b>NOTE<\/b> Elasticsearch is a REST-based search engine that\u2019s often used for aggregating logs. You can find out more at <a href=\"https:\/\/www.elastic.co\/elasticsearch\">https:\/\/www.elastic.co\/elasticsearch<\/a>.<br \/>\n\u6ce8\u610f:Elasticsearch \u662f\u4e00\u4e2a\u57fa\u4e8e REST \u7684\u641c\u7d22\u5f15\u64ce\uff0c\u901a\u5e38\u7528\u4e8e\u805a\u5408\u65e5\u5fd7\u3002\u60a8\u53ef\u4ee5\u5728 <a href=\"https:\/\/www.elastic.co\/elasticsearch\">https:\/\/www.elastic.co\/elasticsearch<\/a> \u4e86\u89e3\u66f4\u591a\u4fe1\u606f\u3002<\/p>\n<p>Elasticsearch is a powerful production-scale engine for storing your logs, but setting it up and running it in production isn\u2019t easy. Even after you\u2019ve got it up and running, there\u2019s a somewhat steep learning curve associated with the query syntax. If you\u2019re interested in something more user-friendly for your structured logging needs, Seq (<a href=\"https:\/\/getseq.net\">https:\/\/getseq.net<\/a>) is a great option. In the next section I\u2019ll show you how adding Seq as a structured logging provider makes analyzing your logs that much easier.<br \/>\nElasticsearch \u662f\u4e00\u4e2a\u5f3a\u5927\u7684\u751f\u4ea7\u89c4\u6a21\u5f15\u64ce\uff0c\u7528\u4e8e\u5b58\u50a8\u60a8\u7684\u65e5\u5fd7\uff0c\u4f46\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u8bbe\u7f6e\u548c\u8fd0\u884c\u5b83\u5e76\u4e0d\u5bb9\u6613\u3002\u5373\u4f7f\u5728\u60a8\u542f\u52a8\u5e76\u8fd0\u884c\u5b83\u4e4b\u540e\uff0c\u4e0e\u67e5\u8be2\u8bed\u6cd5\u76f8\u5173\u7684\u5b66\u4e60\u66f2\u7ebf\u4e5f\u4f1a\u6709\u4e9b\u9661\u5ced\u3002\u5982\u679c\u60a8\u5bf9\u66f4\u7528\u6237\u53cb\u597d\u7684\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u9700\u6c42\u611f\u5174\u8da3\uff0cSeq \uff08<a href=\"https:\/\/getseq.net\">https:\/\/getseq.net<\/a>\uff09 \u662f\u4e00\u4e2a\u4e0d\u9519\u7684\u9009\u62e9\u3002\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u5c06\u5411\u60a8\u5c55\u793a\u5c06 Seq \u6dfb\u52a0\u4e3a\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u5982\u4f55\u4f7f\u5206\u6790\u65e5\u5fd7\u53d8\u5f97\u66f4\u52a0\u5bb9\u6613\u3002<\/p>\n<h3>26.5.1 Adding a structured logging provider to your app<\/h3>\n<p>26.5.1 \u5411\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f<\/p>\n<p>To demonstrate the advantages of structured logging, in this section you\u2019ll configure an app to write logs to Seq. You\u2019ll see that the configuration is essentially identical to unstructured providers, but the possibilities afforded by structured logging make considering it a no-brainer.<br \/>\n\u4e3a\u4e86\u6f14\u793a\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u7684\u4f18\u52bf\uff0c\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u914d\u7f6e\u4e00\u4e2a\u5e94\u7528\u7a0b\u5e8f\u4ee5\u5c06\u65e5\u5fd7\u5199\u5165 Seq\u3002\u60a8\u5c06\u770b\u5230\u8be5\u914d\u7f6e\u4e0e\u975e\u7ed3\u6784\u5316\u63d0\u4f9b\u7a0b\u5e8f\u57fa\u672c\u76f8\u540c\uff0c\u4f46\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7684\u53ef\u80fd\u6027\u4f7f\u5f97\u8003\u8651\u5b83\u53d8\u5f97\u8f7b\u800c\u6613\u4e3e\u3002<\/p>\n<p>Seq is installed on a server or your local machine and collects structured log messages over HTTP, providing a web interface for you to view and analyze your logs. It is currently available as a Windows app or a Linux Docker container. You can install a free version for development, which allows you to experiment with structured logging in general.<br \/>\nSeq \u5b89\u88c5\u5728\u670d\u52a1\u5668\u6216\u672c\u5730\u8ba1\u7b97\u673a\u4e0a\uff0c\u901a\u8fc7 HTTP \u6536\u96c6\u7ed3\u6784\u5316\u65e5\u5fd7\u6d88\u606f\uff0c\u4e3a\u60a8\u63d0\u4f9b\u4e00\u4e2a Web \u754c\u9762\u6765\u67e5\u770b\u548c\u5206\u6790\u60a8\u7684\u65e5\u5fd7\u3002\u5b83\u76ee\u524d\u4ee5 Windows \u5e94\u7528\u7a0b\u5e8f\u6216 Linux Docker \u5bb9\u5668\u7684\u5f62\u5f0f\u63d0\u4f9b\u3002\u60a8\u53ef\u4ee5\u5b89\u88c5\u7528\u4e8e\u5f00\u53d1\u7684\u514d\u8d39\u7248\u672c\uff0c\u8fd9\u6837\u60a8\u5c31\u53ef\u4ee5\u5c1d\u8bd5\u4e00\u822c\u7684\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u3002<\/p>\n<p><b>TIP<\/b> You can download Seq from <a href=\"https:\/\/getseq.net\/Download\">https:\/\/getseq.net\/Download<\/a>.<br \/>\n\u63d0\u793a:\u60a8\u53ef\u4ee5\u4ece <a href=\"https:\/\/getseq.net\/Download\">https:\/\/getseq.net\/Download<\/a> \u4e0b\u8f7d Seq\u3002<\/p>\n<p>From the point of view of your app, the process for adding the Seq provider should be familiar:<br \/>\n\u4ece\u5e94\u7528\u7a0b\u5e8f\u7684\u89d2\u5ea6\u6765\u770b\uff0c\u6dfb\u52a0 Seq \u63d0\u4f9b\u7a0b\u5e8f\u7684\u8fc7\u7a0b\u5e94\u8be5\u5f88\u719f\u6089\uff1a<\/p>\n<ol>\n<li>Install the Seq logging provider using Visual Studio or the .NET CLI with<br \/>\n\u4f7f\u7528 Visual Studio \u6216 .NET CLI \u5b89\u88c5 Seq \u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f<\/li>\n<\/ol>\n<pre><code>dotnet add package Seq.Extensions.Logging<\/code><\/pre>\n<ol start=\"2\">\n<li>Add the Seq logging provider in Program.cs. To add the Seq provider call AddSeq():<br \/>\n\u5728 Program.cs \u4e2d\u6dfb\u52a0 Seq \u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u3002\u8981\u6dfb\u52a0 Seq \u63d0\u4f9b\u7a0b\u5e8f\uff0c\u8bf7\u8c03\u7528 AddSeq\uff08\uff09\uff1a<\/li>\n<\/ol>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\nbuilder.Logging.AddSeq();<\/code><\/pre>\n<p>That\u2019s all you need to add Seq to your app. This will send logs to the default local URL when you have Seq installed in your local environment. The AddSeq() extension method includes additional overloads to customize Seq when you move to production, but this is all you need to start experimenting locally.<br \/>\n\u8fd9\u5c31\u662f\u5c06 Seq \u6dfb\u52a0\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u6240\u9700\u7684\u5168\u90e8\u5185\u5bb9\u3002\u5f53\u60a8\u5728\u672c\u5730\u73af\u5883\u4e2d\u5b89\u88c5\u4e86 Seq \u65f6\uff0c\u8fd9\u4f1a\u5c06\u65e5\u5fd7\u53d1\u9001\u5230\u9ed8\u8ba4\u7684\u672c\u5730 URL\u3002AddSeq\uff08\uff09 \u6269\u5c55\u65b9\u6cd5\u5305\u62ec\u989d\u5916\u7684\u91cd\u8f7d\uff0c\u4ee5\u4fbf\u5728\u60a8\u8fc1\u79fb\u5230\u751f\u4ea7\u73af\u5883\u65f6\u81ea\u5b9a\u4e49 Seq\uff0c\u4f46\u8fd9\u5c31\u662f\u60a8\u5f00\u59cb\u5728\u672c\u5730\u5b9e\u9a8c\u6240\u9700\u7684\u5168\u90e8\u5185\u5bb9\u3002<\/p>\n<p>If you haven\u2019t already, install Seq on your development machine (or run the Docker container) and navigate to the Seq app at <a href=\"http:\/\/localhost:5341\">http:\/\/localhost:5341<\/a>. In a different tab, open your app, and start browsing your app and generating logs. Back in Seq, if you refresh the page, you\u2019ll see a list of logs, something like figure 26.11. Clicking a log expands it and shows you the structured data recorded for the log.<br \/>\n\u5982\u679c\u60a8\u5c1a\u672a\u5728\u5f00\u53d1\u8ba1\u7b97\u673a\u4e0a\u5b89\u88c5 Seq\uff08\u6216\u8fd0\u884c Docker \u5bb9\u5668\uff09\uff0c\u5e76\u5728 <a href=\"http:\/\/localhost:5341\">http:\/\/localhost:5341<\/a> \u5bfc\u822a\u5230 Seq \u5e94\u7528\u7a0b\u5e8f\u3002\u5728\u53e6\u4e00\u4e2a\u9009\u9879\u5361\u4e2d\uff0c\u6253\u5f00\u60a8\u7684\u5e94\u7528\uff0c\u7136\u540e\u5f00\u59cb\u6d4f\u89c8\u60a8\u7684\u5e94\u7528\u5e76\u751f\u6210\u65e5\u5fd7\u3002\u56de\u5230 Seq\uff0c\u5982\u679c\u4f60\u5237\u65b0\u9875\u9762\uff0c\u4f60\u4f1a\u770b\u5230\u4e00\u4e2a\u65e5\u5fd7\u5217\u8868\uff0c\u7c7b\u4f3c\u4e8e\u56fe 26.11\u3002\u5355\u51fb\u65e5\u5fd7\u53ef\u5c06\u5176\u5c55\u5f00\uff0c\u5e76\u663e\u793a\u4e3a\u8be5\u65e5\u5fd7\u8bb0\u5f55\u7684\u7ed3\u6784\u5316\u6570\u636e\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2611.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 26.11 The Seq UI. Logs are presented as a list. You can view the structured logging details of individual logs, view analytics for logs in aggregate, and search by log properties.<br \/>\n\u56fe 26.11 Seq UI\u3002\u65e5\u5fd7\u4ee5\u5217\u8868\u5f62\u5f0f\u663e\u793a\u3002\u60a8\u53ef\u4ee5\u67e5\u770b\u5355\u4e2a\u65e5\u5fd7\u7684\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u8be6\u7ec6\u4fe1\u606f\uff0c\u67e5\u770b\u805a\u5408\u65e5\u5fd7\u7684\u5206\u6790\uff0c\u5e76\u6309\u65e5\u5fd7\u5c5e\u6027\u8fdb\u884c\u641c\u7d22\u3002<\/p>\n<p>ASP.NET Core supports structured logging by treating each captured parameter from your message format string as a key-value pair. If you create a log message using the following format string,<br \/>\nASP.NET Core \u901a\u8fc7\u5c06\u6d88\u606f\u683c\u5f0f\u5b57\u7b26\u4e32\u4e2d\u6355\u83b7\u7684\u6bcf\u4e2a\u53c2\u6570\u89c6\u4e3a\u952e\u503c\u5bf9\u6765\u652f\u6301\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u3002\u5982\u679c\u4f7f\u7528\u4ee5\u4e0b\u683c\u5f0f\u5b57\u7b26\u4e32\u521b\u5efa\u65e5\u5fd7\u6d88\u606f\uff0c<\/p>\n<pre><code>_log.LogInformation(&quot;Loaded {RecipeCount} recipes&quot;, Recipes.Count);<\/code><\/pre>\n<p>the Seq logging provider creates a RecipeCount parameter with a value of Recipes.Count. These parameters are added as properties to each structured log, as you can see in figure 26.11.<br \/>\nSeq \u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u4f1a\u521b\u5efa\u4e00\u4e2a\u503c\u4e3a Recipes.Count \u7684 RecipeCount \u53c2\u6570\u3002\u8fd9\u4e9b\u53c2\u6570\u4f5c\u4e3a\u5c5e\u6027\u6dfb\u52a0\u5230\u6bcf\u4e2a\u7ed3\u6784\u5316\u65e5\u5fd7\u4e2d\uff0c\u5982\u56fe 26.11 \u6240\u793a\u3002<\/p>\n<p>Structured logs are generally easier to read than your standard-issue console output, but their real power comes when you need to answer a specific question. Consider the problem from before, where you see this error:<br \/>\n\u7ed3\u6784\u5316\u65e5\u5fd7\u901a\u5e38\u6bd4\u6807\u51c6\u95ee\u9898\u63a7\u5236\u53f0\u8f93\u51fa\u66f4\u6613\u4e8e\u9605\u8bfb\uff0c\u4f46\u5f53\u60a8\u9700\u8981\u56de\u7b54\u7279\u5b9a\u95ee\u9898\u65f6\uff0c\u5b83\u4eec\u7684\u771f\u6b63\u529f\u80fd\u5c31\u6765\u4e86\u3002\u8003\u8651\u4e4b\u524d\u7684\u95ee\u9898\uff0c\u60a8\u4f1a\u770b\u5230\u4ee5\u4e0b\u9519\u8bef\uff1a<\/p>\n<pre><code>Could not find recipe with id 3245<\/code><\/pre>\n<p>You want to get a feel for how widespread the problem is. The first step would be to identify how many times this error has occurred and to see whether it\u2019s happened to any other recipes. Seq lets you filter your logs, but it also lets you craft SQL queries to analyze your data, so finding the answer to the question takes a matter of seconds, as shown in figure 26.12.<br \/>\n\u60a8\u60f3\u4e86\u89e3\u8fd9\u4e2a\u95ee\u9898\u7684\u666e\u904d\u6027\u3002\u7b2c\u4e00\u6b65\u662f\u786e\u5b9a\u6b64\u9519\u8bef\u53d1\u751f\u4e86\u591a\u5c11\u6b21\uff0c\u5e76\u67e5\u770b\u4efb\u4f55\u5176\u4ed6\u914d\u65b9\u662f\u5426\u53d1\u751f\u8fc7\u6b64\u9519\u8bef\u3002Seq \u5141\u8bb8\u60a8\u8fc7\u6ee4\u65e5\u5fd7\uff0c\u4f46\u5b83\u4e5f\u5141\u8bb8\u60a8\u5236\u4f5c SQL \u67e5\u8be2\u6765\u5206\u6790\u6570\u636e\uff0c\u56e0\u6b64\u627e\u5230\u95ee\u9898\u7684\u7b54\u6848\u9700\u8981\u51e0\u79d2\u949f\uff0c\u5982\u56fe 26.12 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2612.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 26.12 Querying logs in Seq. Structured logging makes log analysis like this example easy.<br \/>\n\u56fe 26.12 \u5728 Seq \u4e2d\u67e5\u8be2\u65e5\u5fd7\u3002\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u4f7f\u50cf\u8fd9\u4e2a\u4f8b\u5b50\u4e00\u6837\u7684\u65e5\u5fd7\u5206\u6790\u53d8\u5f97\u5bb9\u6613\u3002<\/p>\n<p><b>NOTE<\/b> You don\u2019t need query languages like SQL for simple queries, but they make digging into the data easier. Other structured logging providers may provide query languages other than SQL, but the principle is the same as in this Seq example.<br \/>\n\u6ce8\u610f:\u60a8\u4e0d\u9700\u8981\u50cf SQL \u8fd9\u6837\u7684\u67e5\u8be2\u8bed\u8a00\u8fdb\u884c\u7b80\u5355\u7684\u67e5\u8be2\uff0c\u4f46\u5b83\u4eec\u53ef\u4ee5\u66f4\u8f7b\u677e\u5730\u6316\u6398\u6570\u636e\u3002\u5176\u4ed6\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u53ef\u80fd\u4f1a\u63d0\u4f9b SQL \u4ee5\u5916\u7684\u67e5\u8be2\u8bed\u8a00\uff0c\u4f46\u539f\u7406\u4e0e\u6b64 Seq \u793a\u4f8b\u4e2d\u7684\u76f8\u540c\u3002<\/p>\n<p>A quick search shows that you\u2019ve recorded the log message with EventId.Id=12 (the EventId of the warning we\u2019re interested in) 13 times, and every time, the offending RecipeId was 3245. This suggests that there may be something wrong with that recipe specifically, which points you in the right direction to find the problem.<br \/>\n\u5feb\u901f\u641c\u7d22\u663e\u793a\uff0c\u60a8\u5df2\u7ecf\u4f7f\u7528 EventId.Id=12\uff08\u6211\u4eec\u611f\u5174\u8da3\u7684\u8b66\u544a\u7684 EventId\uff09\u8bb0\u5f55\u4e86 13 \u6b21\u65e5\u5fd7\u6d88\u606f\uff0c\u6bcf\u6b21\u8fdd\u89c4\u7684 RecipeId \u90fd\u662f 3245\u3002\u8fd9\u8868\u660e\u8be5\u914d\u65b9\u53ef\u80fd\u5b58\u5728\u95ee\u9898\uff0c\u8fd9\u4e3a\u60a8\u6307\u660e\u4e86\u67e5\u627e\u95ee\u9898\u7684\u6b63\u786e\u65b9\u5411\u3002<\/p>\n<p>More often than not, figuring out errors in production involves logging detective work like this to isolate where the problem occurred. Structured logging makes this process significantly easier, so it\u2019s well worth considering, whether you choose Seq, Elasticsearch, or a different provider.<br \/>\n\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u627e\u51fa\u751f\u4ea7\u4e2d\u7684\u9519\u8bef\u6d89\u53ca\u8bb0\u5f55\u6b64\u7c7b\u4fa6\u63a2\u5de5\u4f5c\u4ee5\u9694\u79bb\u95ee\u9898\u53d1\u751f\u7684\u4f4d\u7f6e\u3002\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u4f7f\u6b64\u8fc7\u7a0b\u53d8\u5f97\u66f4\u52a0\u5bb9\u6613\uff0c\u56e0\u6b64\uff0c\u65e0\u8bba\u60a8\u9009\u62e9 Seq\u3001Elasticsearch \u8fd8\u662f\u5176\u4ed6\u63d0\u4f9b\u5546\uff0c\u90fd\u503c\u5f97\u8003\u8651\u3002<\/p>\n<p>I\u2019ve already described how you can add structured properties to your log messages using variables and parameters from the message. But as you can see in figure 26.11, there are far more properties visible than exist in the message alone.<br \/>\n\u6211\u5df2\u7ecf\u4ecb\u7ecd\u4e86\u5982\u4f55\u4f7f\u7528\u6d88\u606f\u4e2d\u7684\u53d8\u91cf\u548c\u53c2\u6570\u5c06\u7ed3\u6784\u5316\u5c5e\u6027\u6dfb\u52a0\u5230\u65e5\u5fd7\u6d88\u606f\u4e2d\u3002\u4f46\u662f\u6b63\u5982\u4f60\u5728\u56fe 26.11 \u4e2d\u770b\u5230\u7684\uff0c\u53ef\u89c1\u7684\u5c5e\u6027\u6bd4\u5355\u72ec\u7684\u6d88\u606f\u4e2d\u8981\u591a\u5f97\u591a\u3002<\/p>\n<p>Scopes provide a way to add arbitrary data to your log messages. They\u2019re available in some unstructured logging providers, but they shine when used with structured logging providers. In the final section of this chapter I\u2019ll demonstrate how you can use them to add data to your log messages.<br \/>\n\u8303\u56f4\u63d0\u4f9b\u4e86\u4e00\u79cd\u5c06\u4efb\u610f\u6570\u636e\u6dfb\u52a0\u5230\u65e5\u5fd7\u6d88\u606f\u7684\u65b9\u6cd5\u3002\u5b83\u4eec\u5728\u4e00\u4e9b\u975e\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u5546\u4e2d\u53ef\u7528\uff0c\u4f46\u5728\u4e0e\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u5546\u4e00\u8d77\u4f7f\u7528\u65f6\uff0c\u5b83\u4eec\u4f1a\u5927\u653e\u5f02\u5f69\u3002\u5728\u672c\u7ae0\u7684\u6700\u540e\u4e00\u8282\u4e2d\uff0c\u6211\u5c06\u6f14\u793a\u5982\u4f55\u4f7f\u7528\u5b83\u4eec\u5411\u65e5\u5fd7\u6d88\u606f\u6dfb\u52a0\u6570\u636e\u3002<\/p>\n<h3>26.5.2 Using scopes to add properties to your logs<\/h3>\n<p>26.5.2 \u4f7f\u7528\u8303\u56f4\u5411\u65e5\u5fd7\u6dfb\u52a0\u5c5e\u6027<\/p>\n<p>You\u2019ll often find in your apps that you have a group of operations that all use the same data, which would be useful to attach to logs. For example, you might have a series of database operations that all use the same transaction ID, or you might be performing multiple operations with the same user ID or recipe ID. Logging scopes provide a way of associating the same data to every log message in such a group.<br \/>\n\u60a8\u7ecf\u5e38\u4f1a\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u53d1\u73b0\uff0c\u6709\u4e00\u7ec4\u4f5c\u90fd\u4f7f\u7528\u76f8\u540c\u7684\u6570\u636e\uff0c\u8fd9\u5bf9\u4e8e\u9644\u52a0\u5230\u65e5\u5fd7\u975e\u5e38\u6709\u7528\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u80fd\u6709\u4e00\u7cfb\u5217\u6570\u636e\u5e93\u4f5c\uff0c\u8fd9\u4e9b\u4f5c\u90fd\u4f7f\u7528\u76f8\u540c\u7684\u4e8b\u52a1 ID\uff0c\u6216\u8005\u60a8\u53ef\u80fd\u6b63\u5728\u4f7f\u7528\u76f8\u540c\u7684\u7528\u6237 ID \u6216\u914d\u65b9 ID \u6267\u884c\u591a\u4e2a\u4f5c\u3002\u65e5\u5fd7\u8bb0\u5f55\u8303\u56f4\u63d0\u4f9b\u4e86\u4e00\u79cd\u5c06\u76f8\u540c\u6570\u636e\u4e0e\u6b64\u7c7b\u7ec4\u4e2d\u7684\u6bcf\u4e2a\u65e5\u5fd7\u6d88\u606f\u76f8\u5173\u8054\u7684\u65b9\u6cd5\u3002<\/p>\n<p><b>DEFINITION<\/b> Logging scopes are used to group multiple operations by adding relevant data to multiple log message.<br \/>\n\u5b9a\u4e49:\u65e5\u5fd7\u8bb0\u5f55\u8303\u56f4\u7528\u4e8e\u901a\u8fc7\u5c06\u76f8\u5173\u6570\u636e\u6dfb\u52a0\u5230\u591a\u4e2a\u65e5\u5fd7\u6d88\u606f\u6765\u5bf9\u591a\u4e2a\u4f5c\u8fdb\u884c\u5206\u7ec4\u3002<\/p>\n<p>Logging scopes in ASP.NET Core are created by calling ILogger.BeginScope<T>(T state) and providing the state data to be logged. You create scopes inside a using block; any log messages written inside the scope block will have the associated data, whereas those outside won\u2019t.<br \/>\nASP.NET Core \u4e2d\u7684\u65e5\u5fd7\u8bb0\u5f55\u8303\u56f4\u662f\u901a\u8fc7\u8c03\u7528 ILogger.BeginScope\uff08T state\uff09 \u5e76\u63d0\u4f9b\u8981\u8bb0\u5f55\u7684\u72b6\u6001\u6570\u636e\u6765\u521b\u5efa\u7684\u3002\u60a8\u53ef\u4ee5\u5728 using \u5757\u4e2d\u521b\u5efa\u8303\u56f4;\u5199\u5165 scope \u5757\u5185\u7684\u4efb\u4f55\u65e5\u5fd7\u6d88\u606f\u90fd\u5c06\u5305\u542b\u5173\u8054\u7684\u6570\u636e\uff0c\u800c scope \u5757\u5916\u7684\u65e5\u5fd7\u6d88\u606f\u5219\u6ca1\u6709\u3002<\/p>\n<p>Listing 26.8 Adding scope properties to log messages with BeginScope<br \/>\n\u793a\u4f8b 26.8 \u4f7f\u7528 BeginScope \u6dfb\u52a0 scope \u5c5e\u6027\u4ee5\u8bb0\u5f55\u6d88\u606f<\/p>\n<pre><code>_logger.LogInformation(&quot;No, I don&#039;t have scope&quot;);   #A\nusing(_logger.BeginScope(&quot;Scope value&quot;))                #B\nusing(_logger.BeginScope(new Dictionary&lt;string, object&gt;     #C\n    {{ &quot;CustomValue1&quot;, 12345 } }))                          #C\n{\n    _logger.LogInformation(&quot;Yes, I have the scope!&quot;);    #D\n}\n_logger.LogInformation(&quot;No, I lost it again&quot;);      #A<\/code><\/pre>\n<p>\u2776 Log messages written outside the scope block don\u2019t include the scope state.<br \/>\n\u5728 scope \u5757\u4e4b\u5916\u5199\u5165\u7684\u65e5\u5fd7\u6d88\u606f\u4e0d\u5305\u542b scope \u72b6\u6001\u3002<\/p>\n<p>\u2777 Calling BeginScope starts a scope block, with a scope state of \u201cScope value\u201d.<br \/>\n\u8c03\u7528 BeginScope \u5c06\u542f\u52a8\u4e00\u4e2a\u8303\u56f4\u5757\uff0c\u5176\u8303\u56f4\u72b6\u6001\u4e3a\u201c\u8303\u56f4\u503c\u201d\u3002<\/p>\n<p>\u2778 You can pass anything as the state for a scope.<br \/>\n\u4f60\u53ef\u4ee5\u5c06\u4efb\u4f55\u5185\u5bb9\u4f5c\u4e3a scope \u7684\u72b6\u6001\u4f20\u9012\u3002<\/p>\n<p>\u2779 Log messages written inside the scope block include the scope state.<br \/>\n\u5199\u5165 scope \u5757\u5185\u7684\u65e5\u5fd7\u6d88\u606f\u5305\u62ec scope \u72b6\u6001\u3002<\/p>\n<p>The scope state can be any object at all: an int, a string, or a Dictionary, for example. It\u2019s up to each logging provider implementation to decide how to handle the state you provide in the BeginScope call, but typically, it is serialized using ToString().<br \/>\n\u8303\u56f4 state \u53ef\u4ee5\u662f\u4efb\u4f55\u5bf9\u8c61\uff1a\u4f8b\u5982 int\u3001string \u6216 Dictionary\u3002\u7531\u6bcf\u4e2a\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u5b9e\u73b0\u51b3\u5b9a\u5982\u4f55\u5904\u7406\u60a8\u5728 BeginScope \u8c03\u7528\u4e2d\u63d0\u4f9b\u7684\u72b6\u6001\uff0c\u4f46\u901a\u5e38\uff0c\u5b83\u662f\u4f7f\u7528 ToString\uff08\uff09 \u5e8f\u5217\u5316\u7684\u3002<\/p>\n<p><b>TIP<\/b> The most common use for scopes I\u2019ve found is to attach additional key-value pairs to logs. To achieve this behavior in Seq, you need to pass Dictionary&lt;string, object&gt; as the state object. Nicholas Blumhardt, the creator of Serilog and Seq, has examples and the reasoning for this on his blog in the \u201cThe semantics of ILogger.BeginScope()\u201d article: <a href=\"http:\/\/mng.bz\/GxDD\">http:\/\/mng.bz\/GxDD<\/a>.<br \/>\n\u63d0\u793a:\u6211\u53d1\u73b0\u7684 scope \u6700\u5e38\u89c1\u7684\u7528\u9014\u662f\u5c06\u989d\u5916\u7684\u952e\u503c\u5bf9\u9644\u52a0\u5230\u65e5\u5fd7\u3002\u8981\u5728 Seq \u4e2d\u5b9e\u73b0\u6b64\u884c\u4e3a\uff0c\u60a8\u9700\u8981\u5c06 Dictionary&lt;string\uff0c object&gt; \u4f5c\u4e3a\u72b6\u6001\u5bf9\u8c61\u4f20\u9012\u3002Serilog \u548c Seq \u7684\u521b\u5efa\u8005 Nicholas Blumhardt \u5728\u4ed6\u7684\u535a\u5ba2\u201cILogger.BeginScope\uff08\uff09 \u7684\u8bed\u4e49\u201d\u4e00\u6587\u4e2d\u63d0\u4f9b\u4e86\u793a\u4f8b\u548c\u539f\u56e0\uff1a<a href=\"http:\/\/mng.bz\/GxDD\">http:\/\/mng.bz\/GxDD<\/a>\u3002<\/p>\n<p>When the log messages inside the scope block are written, the scope state is captured and written as part of the log, as shown in figure 26.13. The Dictionary&lt;&gt; of key-value pairs is added directly to the log message (CustomValue1), and the remaining state values are added to the Scope property. You will likely find the dictionary approach the more useful of the two, as the added properties are more easily filtered on, as you saw in figure 26.12.<br \/>\n\u5f53\u5199\u5165 scope \u5757\u5185\u7684\u65e5\u5fd7\u6d88\u606f\u65f6\uff0c\u5c06\u6355\u83b7 scope \u72b6\u6001\u5e76\u5c06\u5176\u4f5c\u4e3a\u65e5\u5fd7\u7684\u4e00\u90e8\u5206\u5199\u5165\uff0c\u5982\u56fe 26.13 \u6240\u793a\u3002\u952e\u503c\u5bf9\u7684 Dictionary&lt;&gt; \u5c06\u76f4\u63a5\u6dfb\u52a0\u5230\u65e5\u5fd7\u6d88\u606f \uff08CustomValue1\uff09 \u4e2d\uff0c\u5176\u4f59\u72b6\u6001\u503c\u5c06\u6dfb\u52a0\u5230 Scope \u5c5e\u6027\u4e2d\u3002\u4f60\u53ef\u80fd\u4f1a\u53d1\u73b0\u5b57\u5178\u65b9\u6cd5\u5728\u4e24\u8005\u4e2d\u66f4\u6709\u7528\uff0c\u56e0\u4e3a\u6dfb\u52a0\u7684\u5c5e\u6027\u66f4\u5bb9\u6613\u8fc7\u6ee4\uff0c\u5982\u56fe 26.12 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2613.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 26.13 Adding properties to logs using scopes. Any scope state that is added using the dictionary approach is added as structured logging properties, but other state is added to the Scope property. Adding properties makes it easier to associate related logs with one another.<br \/>\n\u56fe 26.13 \u4f7f\u7528\u8303\u56f4\u5411\u65e5\u5fd7\u6dfb\u52a0\u5c5e\u6027\u3002\u4f7f\u7528\u5b57\u5178\u65b9\u6cd5\u6dfb\u52a0\u7684\u4efb\u4f55\u8303\u56f4\u72b6\u6001\u90fd\u5c06\u6dfb\u52a0\u4e3a\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u5c5e\u6027\uff0c\u4f46\u5176\u4ed6\u72b6\u6001\u5c06\u6dfb\u52a0\u5230 Scope \u5c5e\u6027\u4e2d\u3002\u6dfb\u52a0\u5c5e\u6027\u53ef\u4ee5\u66f4\u8f7b\u677e\u5730\u5c06\u76f8\u5173\u65e5\u5fd7\u5f7c\u6b64\u5173\u8054\u3002<\/p>\n<p>That brings us to the end of this chapter on logging. Whether you use the built-in logging providers or opt to use a third-party provider like Serilog or NLog, ASP.NET Core makes it easy to get detailed logs not only for your app code, but also for the libraries that make up your app\u2019s infrastructure, like Kestrel and EF Core. Whichever you choose, I encourage you to add more logs than you think you\u2019ll need; you\u2019ll thank me when it comes time to track down a problem.<br \/>\n\u8fd9\u5c06\u6211\u4eec\u5e26\u5230\u4e86\u672c\u7ae0\u5173\u4e8e\u65e5\u5fd7\u8bb0\u5f55\u7684\u7ed3\u5c3e\u3002\u65e0\u8bba\u60a8\u662f\u4f7f\u7528\u5185\u7f6e\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u8fd8\u662f\u9009\u62e9\u4f7f\u7528 Serilog \u6216 NLog \u7b49\u7b2c\u4e09\u65b9\u63d0\u4f9b\u7a0b\u5e8f\uff0cASP.NET Core \u90fd\u53ef\u4ee5\u8f7b\u677e\u83b7\u53d6\u5e94\u7528\u7a0b\u5e8f\u4ee3\u7801\u7684\u8be6\u7ec6\u65e5\u5fd7\uff0c\u8fd8\u53ef\u4ee5\u8f7b\u677e\u83b7\u53d6\u6784\u6210\u5e94\u7528\u7a0b\u5e8f\u57fa\u7840\u7ed3\u6784\u7684\u5e93\uff08\u5982 Kestrel \u548c EF Core\uff09\u7684\u8be6\u7ec6\u65e5\u5fd7\u3002\u65e0\u8bba\u60a8\u9009\u62e9\u54ea\u79cd\u65b9\u5f0f\uff0c\u6211\u90fd\u9f13\u52b1\u60a8\u6dfb\u52a0\u6bd4\u60a8\u8ba4\u4e3a\u9700\u8981\u7684\u66f4\u591a\u7684\u65e5\u5fd7;\u5f53\u9700\u8981\u8ffd\u8e2a\u95ee\u9898\u65f6\uff0c\u60a8\u4f1a\u611f\u8c22\u6211\u3002<\/p>\n<p>In the next chapter we\u2019re going to be looking at your ASP.NET Core application from a different point of view. Instead of focusing on the code and logic behind your app, we\u2019re going to look at how you prepare an app for production. You\u2019ll see how to specify the URLs your application uses and how to publish an app so that it can be hosted in IIS. Finally, you\u2019ll learn about the bundling and minification of client-side assets, why you should care, and how to use BundlerMinifier in ASP.NET Core.<br \/>\n\u5728\u4e0b\u4e00\u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u4ece\u4e0d\u540c\u7684\u89d2\u5ea6\u770b\u5f85\u60a8\u7684 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u3002\u6211\u4eec\u4e0d\u4f1a\u5173\u6ce8\u5e94\u7528\u7a0b\u5e8f\u80cc\u540e\u7684\u4ee3\u7801\u548c\u903b\u8f91\uff0c\u800c\u662f\u8981\u4e86\u89e3\u5982\u4f55\u4e3a\u751f\u4ea7\u51c6\u5907\u5e94\u7528\u7a0b\u5e8f\u3002\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u6307\u5b9a\u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528\u7684 URL\uff0c\u4ee5\u53ca\u5982\u4f55\u53d1\u5e03\u5e94\u7528\u7a0b\u5e8f\uff0c\u4ee5\u4fbf\u5b83\u53ef\u4ee5\u6258\u7ba1\u5728 IIS \u4e2d\u3002\u6700\u540e\uff0c\u60a8\u5c06\u4e86\u89e3\u5ba2\u6237\u7aef\u8d44\u4ea7\u7684\u6346\u7ed1\u548c\u7f29\u5c0f\u3001\u4e3a\u4ec0\u4e48\u5e94\u8be5\u5173\u6ce8\uff0c\u4ee5\u53ca\u5982\u4f55\u5728 ASP.NET Core \u4e2d\u4f7f\u7528 BundlerMinifier\u3002<\/p>\n<h2>26.6 Summary<\/h2>\n<p>26.6 \u603b\u7ed3<\/p>\n<p>Logging is critical for quickly diagnosing errors in production apps. You should always configure logging for your application so that logs are written to a durable location such as a filesystem or other service, not just to the console, where they will be lost if the window closes or the server restarts.<br \/>\n\u65e5\u5fd7\u8bb0\u5f55\u5bf9\u4e8e\u5feb\u901f\u8bca\u65ad\u751f\u4ea7\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u9519\u8bef\u81f3\u5173\u91cd\u8981\u3002\u60a8\u5e94\u8be5\u59cb\u7ec8\u4e3a\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u65e5\u5fd7\u8bb0\u5f55\uff0c\u4ee5\u4fbf\u5c06\u65e5\u5fd7\u5199\u5165\u6301\u4e45\u4f4d\u7f6e\uff08\u5982\u6587\u4ef6\u7cfb\u7edf\u6216\u5176\u4ed6\u670d\u52a1\uff09\uff0c\u800c\u4e0d\u4ec5\u4ec5\u662f\u5199\u5165\u63a7\u5236\u53f0\uff0c\u5982\u679c\u7a97\u53e3\u5173\u95ed\u6216\u670d\u52a1\u5668\u91cd\u65b0\u542f\u52a8\uff0c\u65e5\u5fd7\u5c06\u4e22\u5931\u3002<\/p>\n<p>You can add logging to your own services by injecting ILogger<T>, where T is the name of the service. Alternatively, inject ILoggerFactory and call CreateLogger().<br \/>\n\u60a8\u53ef\u4ee5\u901a\u8fc7\u6ce8\u5165 ILogger \u5c06\u65e5\u5fd7\u8bb0\u5f55\u6dfb\u52a0\u5230\u60a8\u81ea\u5df1\u7684\u670d\u52a1\u4e2d\uff0c\u5176\u4e2d T \u662f\u670d\u52a1\u7684\u540d\u79f0\u3002\u6216\u8005\uff0c\u6ce8\u5165 ILoggerFactory \u5e76\u8c03\u7528 CreateLogger\uff08\uff09\u3002<\/p>\n<p>The log level of a message indicates how important it is and ranges from Trace to Critical. Typically, you\u2019ll create many low-importance log messages and a few high-importance log messages.<br \/>\n\u6d88\u606f\u7684\u65e5\u5fd7\u7ea7\u522b\u8868\u793a\u5b83\u7684\u91cd\u8981\u6027\uff0c\u8303\u56f4\u4ece Trace \u5230 Critical \u4e0d\u7b49\u3002\u901a\u5e38\uff0c\u60a8\u5c06\u521b\u5efa\u8bb8\u591a\u4f4e\u91cd\u8981\u6027\u7684\u65e5\u5fd7\u6d88\u606f\u548c\u4e00\u4e9b\u9ad8\u91cd\u8981\u6027\u7684\u65e5\u5fd7\u6d88\u606f\u3002<\/p>\n<p>You specify the log level of a log by using the appropriate extension method of ILogger to create your log. To write an Information level log, use ILogger.LogInformation(message).<br \/>\n\u901a\u8fc7\u4f7f\u7528 ILogger \u7684\u76f8\u5e94\u6269\u5c55\u65b9\u6cd5\u6765\u6307\u5b9a\u65e5\u5fd7\u7684\u65e5\u5fd7\u7ea7\u522b\u6765\u521b\u5efa\u65e5\u5fd7\u3002\u82e5\u8981\u7f16\u5199\u4fe1\u606f\u7ea7\u522b\u65e5\u5fd7\uff0c\u8bf7\u4f7f\u7528 ILogger.LogInformation\uff08message\uff09\u3002<\/p>\n<p>The log category indicates which component created the log. It is typically set to the fully qualified name of the class creating the log, but you can set it to any string if you wish. <code>ILogger&lt;T&gt;<\/code> will have a log category of T.<br \/>\n\u65e5\u5fd7\u7c7b\u522b\u6307\u793a\u521b\u5efa\u65e5\u5fd7\u7684\u7ec4\u4ef6\u3002\u5b83\u901a\u5e38\u8bbe\u7f6e\u4e3a\u521b\u5efa\u65e5\u5fd7\u7684\u7c7b\u7684\u5b8c\u5168\u9650\u5b9a\u540d\u79f0\uff0c\u4f46\u60a8\u53ef\u4ee5\u6839\u636e\u9700\u8981\u5c06\u5176\u8bbe\u7f6e\u4e3a\u4efb\u4f55\u5b57\u7b26\u4e32\u3002<code>ILogger&lt;T&gt;<\/code> \u7684\u65e5\u5fd7\u7c7b\u522b\u4e3a T\u3002<\/p>\n<p>You can format messages with placeholder values, similar to the string.Format method, but with meaningful names for the parameters. Calling logger.LogInfo(&quot;Loading Recipe with id {RecipeId}&quot;, 1234) would create a log reading &quot;Loading Recipe with id 1234&quot;, but it would also capture the value RecipeId=1234. This structured logging makes analyzing log messages much easier.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u5360\u4f4d\u7b26\u503c\u8bbe\u7f6e\u6d88\u606f\u683c\u5f0f\uff0c\u7c7b\u4f3c\u4e8e\u5b57\u7b26\u4e32\u3002Format \u65b9\u6cd5\uff0c\u4f46\u53c2\u6570\u5177\u6709\u6709\u610f\u4e49\u7684\u540d\u79f0\u3002\u8c03\u7528 logger\u3002LogInfo\uff08\u201cLoading Recipe with id {RecipeId}\u201d\uff0c 1234\uff09 \u5c06\u521b\u5efa\u4e00\u4e2a\u65e5\u5fd7\uff0c\u663e\u793a\u201cLoading Recipe with id 1234\u201d\uff0c\u4f46\u5b83\u4e5f\u4f1a\u6355\u83b7\u503c RecipeId=1234\u3002\u8fd9\u79cd\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u4f7f\u5206\u6790\u65e5\u5fd7\u6d88\u606f\u53d8\u5f97\u66f4\u52a0\u5bb9\u6613\u3002<\/p>\n<p>ASP.NET Core includes many logging providers out of the box, including the console, debug, EventLog, and EventSource providers. Alternatively, you can add third-party logging providers.<br \/>\nASP.NET Core \u5305\u542b\u8bb8\u591a\u5f00\u7bb1\u5373\u7528\u7684\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u5305\u62ec console\u3001debug\u3001EventLog \u548c EventSource \u63d0\u4f9b\u7a0b\u5e8f\u3002\u6216\u8005\uff0c\u60a8\u53ef\u4ee5\u6dfb\u52a0\u7b2c\u4e09\u65b9\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u5546\u3002<\/p>\n<p>You can configure multiple ILoggerProvider instances in ASP.NET Core, which define where logs are output. WebApplicationBuilder adds the console and debug providers, and you can add providers using the Logging property.<br \/>\n\u60a8\u53ef\u4ee5\u5728 ASP.NET Core \u4e2d\u914d\u7f6e\u591a\u4e2a ILoggerProvider \u5b9e\u4f8b\uff0c\u8fd9\u4e9b\u5b9e\u4f8b\u5b9a\u4e49\u65e5\u5fd7\u7684\u8f93\u51fa\u4f4d\u7f6e\u3002WebApplicationBuilder \u6dfb\u52a0\u63a7\u5236\u53f0\u548c\u8c03\u8bd5\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 Logging \u5c5e\u6027\u6dfb\u52a0\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<p>You can control logging output verbosity using configuration. WebApplicationBuilder uses the &quot;Logging&quot; configuration section to control output verbosity. You typically filter out more logs in production than when developing your application.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528 configuration \u63a7\u5236\u65e5\u5fd7\u8bb0\u5f55\u8f93\u51fa\u7684\u8be6\u7ec6\u7a0b\u5ea6\u3002WebApplicationBuilder \u4f7f\u7528 \u201cLogging\u201d \u914d\u7f6e\u90e8\u5206\u6765\u63a7\u5236\u8f93\u51fa\u8be6\u7ec6\u7a0b\u5ea6\u3002\u4e0e\u5f00\u53d1\u5e94\u7528\u7a0b\u5e8f\u65f6\u76f8\u6bd4\uff0c\u60a8\u5728\u751f\u4ea7\u4e2d\u7b5b\u9009\u51fa\u7684\u65e5\u5fd7\u901a\u5e38\u66f4\u591a\u3002<\/p>\n<p>Only a single log filtering rule is selected for each logging provider when determining whether to output a log message. The most specific rule is selected based on the logging provider and the category of the log message.<br \/>\n\u5728\u786e\u5b9a\u662f\u5426\u8f93\u51fa\u65e5\u5fd7\u6d88\u606f\u65f6\uff0c\u4ec5\u4e3a\u6bcf\u4e2a\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u9009\u62e9\u4e00\u4e2a\u65e5\u5fd7\u7b5b\u9009\u89c4\u5219\u3002\u6839\u636e\u65e5\u5fd7\u8bb0\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u548c\u65e5\u5fd7\u6d88\u606f\u7684\u7c7b\u522b\u9009\u62e9\u6700\u5177\u4f53\u7684\u89c4\u5219\u3002<\/p>\n<p>Structured logging involves recording logs so that they can be easily queried and filtered, instead of the default unstructured format that\u2019s output to the console. This makes analyzing logs, searching for problems, and identifying patterns easier.<br \/>\n\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u6d89\u53ca\u8bb0\u5f55\u65e5\u5fd7\uff0c\u4ee5\u4fbf\u53ef\u4ee5\u8f7b\u677e\u67e5\u8be2\u548c\u7b5b\u9009\u65e5\u5fd7\uff0c\u800c\u4e0d\u662f\u8f93\u51fa\u5230\u63a7\u5236\u53f0\u7684\u9ed8\u8ba4\u975e\u7ed3\u6784\u5316\u683c\u5f0f\u3002\u8fd9\u4f7f\u5f97\u5206\u6790\u65e5\u5fd7\u3001\u641c\u7d22\u95ee\u9898\u548c\u8bc6\u522b\u6a21\u5f0f\u53d8\u5f97\u66f4\u52a0\u5bb9\u6613\u3002<\/p>\n<p>You can add properties to a structured log by using scope blocks. A scope block is created by calling ILogger.BeginScope<T>(state) in a using block. The state can be any object and is added to all log messages inside the scope block.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u8303\u56f4\u5757\u5c06\u5c5e\u6027\u6dfb\u52a0\u5230\u7ed3\u6784\u5316\u65e5\u5fd7\u4e2d\u3002\u901a\u8fc7\u5728 using \u5757\u4e2d\u8c03\u7528 ILogger.BeginScope\uff08state\uff09 \u6765\u521b\u5efa\u8303\u56f4\u5757\u3002state \u53ef\u4ee5\u662f\u4efb\u4f55\u5bf9\u8c61\uff0c\u5e76\u6dfb\u52a0\u5230 scope \u5757\u5185\u7684\u6240\u6709\u65e5\u5fd7\u6d88\u606f\u4e2d\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>26 Monitoring and troubleshooting errors with logging 26 \u4f7f\u7528\u65e5\u5fd7\u8bb0\u5f55\u76d1\u63a7\u548c\u6392\u9664\u9519\u8bef This chapter covers \u672c\u7ae0\u6db5\u76d6 \u2022 Understanding the components of a log message \u4e86\u89e3\u65e5\u5fd7\u6d88\u606f\u7684\u7ec4\u6210\u90e8\u5206 \u2022 Writing logs to multiple output locations \u5c06\u65e5\u5fd7\u5199\u5165\u591a\u4e2a\u8f93\u51fa\u4f4d\u7f6e \u2022 Controlling log verbosity in different environments using filtering \u4f7f\u7528\u7b5b\u9009\u63a7\u5236\u4e0d\u540c\u73af\u5883\u4e2d\u7684\u65e5\u5fd7\u8be6\u7ec6\u7a0b\u5ea6 \u2022 Using structured logging to make logs searchable \u4f7f\u7528\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u4f7f\u65e5\u5fd7\u53ef\u641c\u7d22 Logging is one of those topics [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-623","post","type-post","status-publish","format-standard","hentry","category-csharp"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/623","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=623"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/623\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=623"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=623"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=623"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}