मैं Startup.cs के भीतर से लॉग कैसे लिखता हूं


117

एक .net कोर ऐप जो स्टार्टअप पर विफल हो रहा है, को डिबग करने के लिए, मैं स्टार्टअप के भीतर से लॉग लिखना चाहूंगा। फाइल। मेरे पास उस फ़ाइल के भीतर लॉगिंग सेटअप है, जिसका उपयोग स्टार्टअप के भीतर बाकी ऐप में किया जा सकता है। फ़ाइल, लेकिन यह सुनिश्चित नहीं करना चाहिए कि स्टार्टअप के भीतर से लॉग कैसे लिखें।

जवाबों:


183

.नेट कोर 3.1

दुर्भाग्य से, ASP.NET Core 3.0 के लिए, स्थिति फिर से थोड़ी अलग है। डिफ़ॉल्ट टेम्प्लेट HostBuilder(इसके बजाय WebHostBuilder) का उपयोग करते हैं जो एक नया जेनेरिक होस्ट सेट करता है जो वेब अनुप्रयोगों तक सीमित नहीं, कई अलग-अलग अनुप्रयोगों की मेजबानी कर सकता है। इस नए होस्ट का एक हिस्सा दूसरे निर्भरता इंजेक्शन कंटेनर का निष्कासन भी है जो पहले वेब होस्ट के लिए मौजूद था। अंततः इसका मतलब है कि आप किसी भी निर्भरता को वर्ग IConfigurationमें शामिल करने में सक्षम नहीं होंगे Startup। इसलिए आप ConfigureServicesविधि के दौरान लॉग इन नहीं कर पाएंगे । हालाँकि, आप लॉगर को Configureविधि में इंजेक्ट कर सकते हैं और वहाँ लॉग इन कर सकते हैं:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger<Startup> logger)
{
    logger.LogInformation("Configure called");

    // …
}

यदि आपको पूरी तरह से भीतर प्रवेश करने की आवश्यकता है ConfigureServices, तो आप उस का उपयोग करना जारी रख सकते हैं WebHostBuilderजो उस विरासत का निर्माण करेगा जो WebHostलकड़हारे को Startupकक्षा में इंजेक्ट कर सकता है । ध्यान दें कि यह संभावना है कि भविष्य में किसी बिंदु पर वेब होस्ट हटा दिया जाएगा। तो आपको एक समाधान खोजने की कोशिश करनी चाहिए जो आपके लिए बिना लॉग इन किए काम करता है ConfigureServices


.NET कोर 2.x

यह ASP.NET कोर 2.0 की रिलीज के साथ काफी बदल गया है। ASP.NET Core 2.x में, होस्ट बिल्डर में लॉगिंग बनाई जाती है। इसका मतलब यह है कि लॉगिंग डिफ़ॉल्ट रूप से DI के माध्यम से उपलब्ध है और इसे Startupकक्षा में इंजेक्ट किया जा सकता है :

public class Startup
{
    private readonly ILogger<Startup> _logger;

    public IConfiguration Configuration { get; }

    public Startup(ILogger<Startup> logger, IConfiguration configuration)
    {
        _logger = logger;
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        _logger.LogInformation("ConfigureServices called");

        // …
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        _logger.LogInformation("Configure called");

        // …
    }
}

4
धन्यवाद। यह आश्चर्यजनक है कि आप सरल सवालों के जवाब की तलाश में कितना समय जला सकते हैं। @poke धन्यवाद (फिर से) मुझे सूचित करने के लिए कि मेरे विकल्प क्या हैं। ये जानकारी तुम्हें कहाँ से मिली? मैंने पुष्टि की है कि मैं कॉन्फिगर में सामान लॉग इन कर सकता हूं, जो एक तेज छड़ी के साथ आंखों में एक प्रहार (इच्छित उद्देश्य) के लिए बेहतर है लेकिन शायद कॉन्फिगरस्वाइस के दौरान सक्षम होने के रूप में भयानक नहीं है। मेरे मामले में मैं लॉग इन करना चाहूंगा या नहीं, मुझे एनवी सेटिंग्स मिलीं, शायद उन्हें लॉग में पोस्ट करें। कोई पाँसा नहीं? आहें ... यकीन नहीं होता कि यह इतना कठिन क्यों होना चाहिए। लेकिन कम से कम, इस पोस्ट के लिए धन्यवाद, मुझे पता है कि मैं क्या कर सकता हूं और क्या नहीं।
वेल्स

3
@ 3.0 में, यह "कठिन" है क्योंकि जब तक ConfigureServicesरन होंगे, लकड़हारा वास्तव में अभी तक मौजूद नहीं है। तो आप उस बिंदु पर लॉग इन नहीं कर पाएंगे क्योंकि अभी तक कोई लकड़हारा नहीं है। प्लस साइड पर, यह अभी भी आपको लकड़हारा को कॉन्फ़िगर करने की क्षमता देता है ConfigureServicesक्योंकि यह सभी एक ही डीआई कंटेनर है (जो वास्तव में अच्छा है)। - यदि आपको सामान को लॉग इन करने की आवश्यकता है, तो आप उदाहरण के लिए अलग से जानकारी एकत्र कर सकते हैं (उदाहरण के लिए एक सूची में) और फिर लॉग आउट होते ही लॉग आउट करें।
प्रहार करें

आपके भीतर .NET 3.1वर्तमान में वापस गिरने के बिनाConfigureServices विधि के भीतर लॉग इन कर सकते हैं । नीचे दिए गए उत्तर का उपयोग करें: stackoverflow.com/a/61488490/2877982WebHostBuilder
Aage

2
@Aage के इसके कई नुकसान होंगे हालांकि: आपको अपना पूर्ण लॉगिंग कॉन्फ़िगरेशन दोहराना होगा, लॉगिंग कॉन्फ़िगरेशन आपके एप्लिकेशन कॉन्फ़िगरेशन (जैसे कि ऐपसेटिंग आदि में लॉग स्तर कॉन्फ़िगर किए गए) को भी प्रतिबिंबित नहीं करेगा, और आप आम तौर पर एक दूसरे लॉगिंग इन्फ्रास्ट्रक्चर की स्थापना कर रहे हैं। मैं अब भी आपको एक समाधान खोजने के लिए सुझाव दूंगा कि आप डीआई सेटअप के दौरान पूरी तरह से लॉगिंग से कैसे बच सकते हैं।
पोक करें

@ मैं इस बारे में नहीं सोचा था। वास्तव में मैं केवल स्पष्ट नियंत्रक निर्माण चाहता हूं Startup.csताकि मेरे ( केवल एक निर्भरता को भूल जाने पर कंपाइलर त्रुटियां मिलें) केवल कस्टम निर्भरता दर्ज करने के बजाय । इसलिए मुझे इन लॉगर्स को हल करने की आवश्यकता है। लेकिन यह थोड़ा हैकी हो सकता है, हाँ।
आवेश

37

विकल्प 1: स्टार्टअप में सीधे लॉग (जैसे सेरिलॉग) का उपयोग करें-

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        Log.Logger = new LoggerConfiguration()
           .MinimumLevel.Debug()
           .WriteTo.RollingFile(Path.Combine(env.ContentRootPath, "Serilog-{Date}.txt"))
           .CreateLogger();

        Log.Information("Inside Startup ctor");
        ....
    }

    public void ConfigureServices(IServiceCollection services)
    {
        Log.Information("ConfigureServices");
        ....
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        Log.Information("Configure");
        ....
    }

आउटपुट:

serilog

Asp.net-core एप्लिकेशन में Serilog सेटअप करने के लिए, GitHub पर Serilog.AspNetCore पैकेज देखें


विकल्प 2: प्रोग्राम में लॉगिंग कॉन्फ़िगर करें। इस तरह से-

var host = new WebHostBuilder()
            .UseKestrel()
            .ConfigureServices(s => {
                s.AddSingleton<IFormatter, LowercaseFormatter>();
            })
            .ConfigureLogging(f => f.AddConsole(LogLevel.Debug))
            .UseStartup<Startup>()
            .Build();

host.Run();

इस तरह स्टार्टअप में उपयोगकर्ता loggerFactory-

public class Startup
{
    ILogger _logger;
    IFormatter _formatter;
    public Startup(ILoggerFactory loggerFactory, IFormatter formatter)
    {
        _logger = loggerFactory.CreateLogger<Startup>();
        _formatter = formatter;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        _logger.LogDebug($"Total Services Initially: {services.Count}");

        // register services
        //services.AddSingleton<IFoo, Foo>();
    }

    public void Configure(IApplicationBuilder app, IFormatter formatter)
    {
        // note: can request IFormatter here as well as via constructor
        _logger.LogDebug("Configure() started...");
        app.Run(async (context) => await context.Response.WriteAsync(_formatter.Format("Hi!")));
        _logger.LogDebug("Configure() complete.");
    }
}

पूरा विवरण इस लिंक पर उपलब्ध है


7

.Net Core 3.1 के अनुसार , आप सीधे LogFactory का उपयोग करके एक लकड़हारा बना सकते हैं।

var loggerFactory = LoggerFactory.Create(builder =>
{
     builder.AddConsole();                
});

ILogger logger = loggerFactory.CreateLogger<Startup>();
logger.LogInformation("Example log message");

Log4net के लिए यह करने के लिए नीचे फोड़े ILogger logger = LoggerFactory.Create(builder => builder.AddLog4Net()).CreateLogger<Startup>();। हालाँकि, यदि आप केवल अपवादों को लॉग करते हैं तो यह विंडोज ईवेंटलॉग (जब आईआईएस का उपयोग करते हुए) में पहले से ही दिखाई देता है, उससे अधिक प्रकट नहीं होगा।
लुइस सोमरस

6

.NET कोर 3.0 के लिए आधिकारिक डॉक्स में यह कहना है: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-3.0#create-logs-in-startup

Startup.ConfigureServicesविधि में DI कंटेनर सेटअप पूरा होने से पहले लॉग लिखना समर्थित नहीं है:

  • Startupकंस्ट्रक्टर में लकड़हारा इंजेक्शन समर्थित नहीं है।
  • Startup.ConfigureServicesविधि हस्ताक्षर में लकड़हारा इंजेक्शन समर्थित नहीं है

लेकिन जैसा कि वे कहते हैं कि डॉक्स में आप एक ऐसी सेवा को कॉन्फ़िगर कर सकते हैं जो ILogger पर निर्भर करती है, इसलिए यदि आपने एक क्लास StartupLogger लिखा है:

public class StartupLogger
{
    private readonly ILogger _logger;

    public StartupLogger(ILogger<StartupLogger> logger)
    {
        _logger = logger;
    }

    public void Log(string message)
    {
        _logger.LogInformation(message);
    }
}

फिर Startup.ConfigureServices में सेवा जोड़ते हैं, तो आपको DI कंटेनर तक पहुंचने के लिए सेवा प्रदाता का निर्माण करना होगा:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton(provider =>
    {
        var service = provider.GetRequiredService<ILogger<StartupLogger>>();
        return new StartupLogger(service);
    });
    var logger = services.BuildServiceProvider().GetRequiredService<StartupLogger>();
    logger.Log("Startup.ConfigureServices called");
}

संपादित करें: यह एक कंपाइलर चेतावनी पैदा करता है, आपके स्टार्टअप वर्ग को डिबग करने के लिए यह ठीक होना चाहिए, लेकिन उत्पादन के लिए नहीं:

Startup.cs (39, 32): [ASP0000] कॉलिंग सेवाओं की एक अतिरिक्त कॉपी में आवेदन कोड के परिणाम से 'BuildServiceProvider' का निर्माण किया जा रहा है। निर्भरता इंजेक्शन सेवाओं जैसे 'विकल्प कॉन्फ़िगर करें' जैसे विकल्पों पर विचार करें।


5

आधिकारिक समाधान वर्तमान में इस तरह एक स्थानीय लकड़हारा सेटअप करने के लिए है:

    using var loggerFactory = LoggerFactory.Create(builder =>
    {
        builder.SetMinimumLevel(LogLevel.Information);
        builder.AddConsole();
        builder.AddEventSourceLogger();
    });
    var logger = loggerFactory.CreateLogger("Startup");
    logger.LogInformation("Hello World");

इसे भी देखें: https://github.com/dotnet/aspnetcore/issues/9337#issuecomment-539859667


4

मैं ILogger इंटरफ़ेस के साथ "लकड़हारा बफर" को लागू करने वाले 3 पार्टी लॉगर्स से बचने वाले समाधान का उपयोग करता हूं ।

public class LoggerBuffered : ILogger
{
    class Entry
    {
        public LogLevel _logLevel;
        public EventId  _eventId;
        public string   _message;
    }
    LogLevel            _minLogLevel;
    List<Entry>         _buffer;
    public LoggerBuffered(LogLevel minLogLevel)
    {
        _minLogLevel = minLogLevel;
        _buffer = new List<Entry>();
    }
    public IDisposable BeginScope<TState>(TState state)
    {
        return null;
    }

    public bool IsEnabled(LogLevel logLevel)
    {
        return logLevel >= _minLogLevel;
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        if (IsEnabled(logLevel)) {
            var str = formatter(state, exception);
            _buffer.Add(new Entry { _logLevel = logLevel, _eventId = eventId, _message = str });
        }
    }
    public void CopyToLogger (ILogger logger)
    {
        foreach (var entry in _buffer)
        {
            logger.Log(entry._logLevel, entry._eventId, entry._message);
        }
        _buffer.Clear();
    }
}

स्टार्टअप में उपयोग करना आसान है। निश्चित रूप से आप कॉन्फ़िगर के कॉल के बाद लॉग आउटपुट प्राप्त करते हैं। लेकिन इससे बेहतर कुछ नहीं। :

public class Startup
{
ILogger         _logger;

public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
    _logger = new LoggerBuffered(LogLevel.Debug);
    _logger.LogInformation($"Create Startup {env.ApplicationName} - {env.EnvironmentName}");

}

public void ConfigureServices(IServiceCollection services)
{
    _logger.LogInformation("ConfigureServices");
    services.AddControllersWithViews();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
    (_logger as LoggerBuffered).CopyToLogger(logger);
    _logger = logger;   // Replace buffered by "real" logger
    _logger.LogInformation("Configure");

    if (env.IsDevelopment())

1

मुख्य कोड:

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
}

CreateDefaultBuilder एक डिफ़ॉल्ट कंसोल लकड़हारा सेट करता है।

... कंसोल और डीबग आउटपुट में लॉग करने के लिए ILoggerFactory कॉन्फ़िगर करता है

स्टार्टअप कोड:

using Microsoft.Extensions.Logging;
...
public class Startup
{
    private readonly ILogger _logger;

    public Startup(IConfiguration configuration, ILoggerFactory logFactory)
    {
        _logger = logFactory.CreateLogger<Startup>();
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        _logger.LogInformation("hello stackoverflow");
    }

मुझे काम करने के लिए आईलॉगर का इंजेक्शन नहीं मिला, लेकिन शायद इसलिए कि यह कोई नियंत्रक नहीं है। अधिक जानकारी का स्वागत है!

refs:


0

उपरोक्त में से किसी भी उत्तर ने मेरे लिए काम नहीं किया। मैं NLog का उपयोग कर रहा हूं, और यहां तक ​​कि एक नया ServiceCollection का निर्माण कर रहा हूं, जो किसी भी सेवा संग्रह पर .CreateBuilder () का निर्माण कर रहा है, एक लॉगिंग सेवा बना रहा है ... इनमें से कोई भी ConfigureServices के दौरान लॉग फ़ाइल में नहीं लिखा जाएगा।

समस्या यह है कि ServiceCollection के बनने के बाद तक लॉगिंग करना वास्तव में कोई बात नहीं है, और यह ConfigureServices के दौरान नहीं बनाया गया है।

मूल रूप से मुझे बस (आवश्यकता) लॉग इन करना है जो कि एक कॉन्फ़िगरेशन एक्सटेंशन विधि में स्टार्टअप के दौरान चल रहा है, क्योंकि एकमात्र टीयर जिस पर मुझे समस्या है वह PROD है, जहां मैं डिबगर संलग्न नहीं कर सकता।

मेरे लिए काम करने वाला समाधान पुराने .NET फ्रेमवर्क NLog विधि का उपयोग कर रहा था: private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); विस्तार विधि वर्ग में उस अधिकार को जोड़ा, और मैं कॉन्फ़िगर और सेवाओं के दौरान एक लॉग ("लॉग") में लिखने में सक्षम था।

मुझे पता नहीं है कि यह वास्तव में उत्पादन कोड में रिलीज करने के लिए एक अच्छा विचार है (मुझे नहीं पता कि .NET नियंत्रित ILogger और यह NLog.ILogger किसी भी बिंदु पर संघर्ष करेगा), लेकिन मुझे केवल यह देखने के लिए इसकी आवश्यकता थी कि क्या हो रहा था पर।


-1

मैं फ़ाइल में Nlog के साथ एक लकड़हारा बनाकर ऐसा करने में कामयाब रहा, तो स्टार्टअप विधियों के भीतर इसका उपयोग करें।

private readonly NLog.Logger _logger = new NLog.LogFactory().GetCurrentClassLogger();

1
जब यह काम करता है, तो मैं ASP.NET कोर और निर्भरता इंजेक्शन (DI) के साथ आने वाले मानक इंटरफेस का उपयोग करने की सलाह दूंगा - या तो लॉग-इन के लिए अंतर्निहित या तीसरी पार्टी -। इंटरफेस का उपयोग करके आप क) यदि आवश्यक हो तो प्रदान की गई लॉगिंग को बदल सकते हैं और बी) जब आप कक्षाओं (जैसे नियंत्रकों) का परीक्षण करते हैं, जहां आप ILogger <TController> को एक सेवा के रूप में इंजेक्ट करते हैं तो उनका मजाक उड़ाना आसान हो जाता है।
मैनफ्रेड

मैंने ठीक उसी चीज़ का अपना उत्तर पोस्ट करने के बाद पहली बार इसे देखा। @ मान लिया कि सिर्फ एक और तरीका नहीं है जो काम करता है। मैं System.IO.File.Write()तरीकों के अलावा अन्य अनुमान लगाता हूं ।
एमरी

-2

बस स्टार्टअप में लॉग इन करने के लिए नीचे दी गई लाइन का उपयोग करें

Log.Information("App started.");
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.