Làm cách nào để thay đổi vị trí tệp theo lập trình?


75

Tôi hoàn toàn mới đối với Log4net. Tôi đã quản lý để đạt được điều gì đó bằng cách thêm tệp cấu hình và ghi nhật ký đơn giản. Tôi đã mã hóa giá trị để được "C:\temp\log.txt"nhưng điều này không đủ tốt.

Nhật ký phải chuyển đến các thư mục đặc biệt

path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);

và đường dẫn này thay đổi tùy thuộc vào việc bạn đang sử dụng Windows Server 2008 hay Windows XP hoặc Vista, v.v.

Làm cách nào để tôi có thể thay đổi vị trí của tệp trong log4net theo lập trình?

Đây là những gì tôi đã làm:

<configSections>
<section name="log4net"
         type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
</configSections>
<log4net>         
    <root>
        <level value="DEBUG" />
        <appender-ref ref="LogFileAppender" />
    </root>
    <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
        <param name="File" value="C:\temp\log.txt" />
        <param name="AppendToFile" value="true" />
        <rollingStyle value="Size" />
        <maxSizeRollBackups value="10" />
        <maximumFileSize value="10MB" />
        <staticLogFileName value="true" />
        <layout type="log4net.Layout.PatternLayout">
            <param name="ConversionPattern" value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n" />
        </layout>
    </appender>
</log4net>

class Program
{
    protected static readonly ILog log = LogManager.GetLogger(typeof(Program));

    static void Main(string[] args)
    {
        log4net.Config.XmlConfigurator.Configure();
        log.Warn("Log something");

        path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);


        // How can I change where I log stuff?
    }
}

Chỉ cần tìm ra cách tôi có thể thay đổi để đăng nhập mọi thứ vào nơi tôi muốn.

Bất kỳ đề xuất? Cảm ơn rất nhiều


Bạn cần tìm hiểu qua IAppenders của trình ghi nhật ký của mình và đặt FileAppender.File thành đường dẫn xuất yêu cầu của bạn. Đây là một ví dụ thực sự tốt .
Cam Soper 8/10/09

Câu trả lời:


89

log4net có thể xử lý điều này cho bạn. Bất kỳ thuộc tính appender nào của kiểu chuỗi đều có thể được định dạng, trong trường hợp này, bằng cách sử dụng trình xử lý tùy chọn log4net.Util.PatternString . PatternString thậm chí còn hỗ trợ enum SpecialFolder cho phép cấu hình trang nhã sau:

<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender" >
    <file type="log4net.Util.PatternString" 
        value="%envFolderPath{CommonApplicationData}\\test.txt" />
    ...
</appender>

Đây là một bài kiểm tra đơn vị chứng minh bánh pudding:

[Test]
public void Load()
{
    XmlConfigurator.Configure();
    var fileAppender = LogManager.GetRepository()
        .GetAppenders().First(appender => appender is RollingFileAppender);

    var expectedFile = 
        Path.Combine(
            Environment.GetFolderPath(
                Environment.SpecialFolder.CommonApplicationData),
                "test.txt");

    Assert.That(fileAppender, 
        Is.Not.Null & Has.Property("File").EqualTo(expectedFile));
}

Kiểm tra sau xác minh rằng log4net thực sự ghi vào đĩa (về cơ bản làm cho đây là kiểm tra "tích hợp", không phải kiểm tra đơn vị, nhưng chúng tôi sẽ để nó ở đó bây giờ):

[Test]
public void Log4net_WritesToDisk()
{
    var expectedFile = 
        Path.Combine(
            Environment.GetFolderPath(
                Environment.SpecialFolder.CommonApplicationData),
                "test.txt");

    if (File.Exists(expectedFile))
        File.Delete(expectedFile);

    XmlConfigurator.Configure();

    var log = LogManager.GetLogger(typeof (ConfigTest));
    log.Info("Message from test");

    LogManager.Shutdown();

    Assert.That(File.ReadAllText(expectedFile), 
        Text.Contains("Message from test"));
}

NB: Tôi thực sự khuyên bạn nên sử dụng cú pháp thuộc tính nhỏ gọn được trình bày trong ví dụ trên. Việc xóa tất cả "<property name =" đó sẽ làm cho cấu hình của bạn dễ đọc hơn nhiều.


1
Xin chào THanks Tôi đã thử cách này nhưng vẫn không đăng nhập được vào ứng dụng Dữ liệu Tôi đã xem trên web, tôi đã tìm thấy một thứ gọi là PatternString nhưng tôi không biết cách sử dụng nó. Có ai có một ví dụ?

@brix - Câu trả lời ban đầu của tôi không hoạt động, vì vậy tôi phải chứng minh với bản thân rằng log4net có thể làm điều này. PatternString sự là giải pháp :)
Peter Lillevold

2
% envFolderPath {} dường như không phải là một phần của bản phát hành (1.2.10) hiện tại của log4net. Tôi đã phải kéo r606477 từ kho lưu trữ phiên bản phụ của họ để bật tính năng rất hữu ích này. Tôi mong đợi điều này sẽ được đưa vào bản phát hành (1.2.11) tiếp theo.
Rodney Schuler

1
@rschuler: Tôi đã thêm một câu trả lời sẽ hoạt động với 1.2.10, xem bên dưới
codeulike

3
Từ câu trả lời của @ JackAce bên dưới, sau khi đặt lại đường dẫn tệp, hãy nhớ gọi ".ActivateOptions ()" để kích hoạt nó. Gọi .file sẽ thiết lập nó nhưng nó sẽ không được sử dụng cho đến khi gọi ActivateOptions
Jeffrey Knight

46

Tôi đã tìm thấy một đột biến của mã này trong các mạng xen kẽ:

XmlConfigurator.Configure();
log4net.Repository.Hierarchy.Hierarchy h =
(log4net.Repository.Hierarchy.Hierarchy) LogManager.GetRepository();
foreach (IAppender a in h.Root.Appenders)
{
    if (a is FileAppender)
    {
        FileAppender fa = (FileAppender)a;
        // Programmatically set this to the desired location here
        string logFileLocation = @"C:\MySpecialFolder\MyFile.log";

        // Uncomment the lines below if you want to retain the base file name
        // and change the folder name...
        //FileInfo fileInfo = new FileInfo(fa.File);
        //logFileLocation = string.Format(@"C:\MySpecialFolder\{0}", fileInfo.Name);

        fa.File = logFileLocation;
        fa.ActivateOptions();
        break;
    }
}

Điều này làm việc cho tôi. Ứng dụng của chúng tôi cần đặt tệp nhật ký vào thư mục có chứa số phiên bản của ứng dụng dựa trên tệp AssemblyInfo.cs.

Bạn sẽ có thể đặt logFileLocation theo chương trình (ví dụ: bạn có thể sử dụng Server.MapPath () nếu đây là một ứng dụng web) cho phù hợp với nhu cầu của bạn.


4
Tôi cảm thấy như thế này kiểm soát nhiều hơn vị trí tệp.
fregas

16

Có vẻ như câu trả lời của Peter không hoạt động cho Log4net v1.2.10.0. Một phương pháp thay thế được mô tả ở đây .

Về cơ bản, phương pháp là triển khai một trình chuyển đổi mẫu tùy chỉnh cho tệp cấu hình log4net.

Đầu tiên hãy thêm lớp này vào dự án của bạn:

public class SpecialFolderPatternConverter : log4net.Util.PatternConverter
{
    override protected void Convert(System.IO.TextWriter writer, object state)
    {
        Environment.SpecialFolder specialFolder = (Environment.SpecialFolder)Enum.Parse(typeof(Environment.SpecialFolder), base.Option, true);
        writer.Write(Environment.GetFolderPath(specialFolder));
    }
}

Sau đó, thiết lập tham số Tệp của FileAppender của bạn như sau:

<file type="log4net.Util.PatternString">
    <converter>
      <name value="folder" />
      <type value="MyAppName.SpecialFolderPatternConverter,MyAppName" />
    </converter>
    <conversionPattern value="%folder{CommonApplicationData}\\SomeOtherFolder\\log.txt" />
  </file>

Về cơ bản, %foldernó yêu cầu nó nhìn vào bộ chuyển đổi được gọi là foldernó trỏ nó đến lớp SpecialFolderPatternConverter. Sau đó, nó gọi Convertlớp đó, truyền vào giá trị enum CommonApplicationData (hoặc bất cứ thứ gì).


Cảm ơn vì điều đó. btw, Ứng dụng trong MyAppName Tôi nghĩ đề cập đến Dự án hơn là Ứng dụng.
Jamie Kitson

Đây là tùy chọn duy nhất hoạt động nếu bạn đang xem tệp log4net.config để biết các thay đổi ( logging.apache.org/log4net/release/sdk/html/… )
cbp

7

Làm thế nào về một đơn giản:

XmlConfigurator.LogFullFilename = @"c:\ProgramData\MyApp\Myapp.log";

Tại sao nó lại phức tạp để làm một việc thực sự đơn giản?


12
Bởi vì, đường dẫn thay đổi tùy thuộc vào việc bạn đang ở trong windows Server 2008 hay winxp hay vista, v.v ... Trong XP không có thư mục c: \ ProgramData, chỉ có trong Win7 / Vista. Vì vậy, nếu chúng tôi triển khai ứng dụng này, nó phải tương thích với tất cả các hệ điều hành. :-) Mã hóa khó không phải là một thực hành tốt.
Irshad

7
Tôi đang sử dụng log4net v2.0.3 và thuộc tính này không khả dụng trên XmlConfigurator. Chắc hẳn đã bị xóa kể từ khi câu trả lời được đăng.
Appetere

Cảm ơn Jason đã sửa tiếng Anh của tôi, đây không phải là ngôn ngữ chính của tôi;) Cảm ơn!
Eric

@Irshad: có, nhưng chúng tôi có thể đọc cấu hình từ cơ sở dữ liệu (ví dụ). Nếu chúng ta có thể thay đổi con đường này lập trình, đôi khi nó tốt hơn
Hoàng Long

4

Điều này đã làm việc cho tôi:

  <log4net>
    <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
..
      <file value="${APPDATA}\MyApp\MyApp Client\logs\Log.txt"/>
..
  </log4net>

Nếu cần ghi vào các thư mục đặc biệt, tôi tìm thấy sự trợ giúp ở đây (ví dụ thứ 2 và thứ 3).

Biên tập:

Để trả lời OP .. Điều này hoạt động cho khu vực 'tất cả người dùng':

      ...
      <file value="${ALLUSERSPROFILE}\MyApp\MyApp Client\logs\Log.txt"/>
      ...

Đây thường là "C: \ ProgramData" trong các phiên bản Windows mới hơn.

Cũng xem những điều này:
Làm thế nào để chỉ định thư mục dữ liệu ứng dụng chung cho log4net? == https://stackoverflow.com/a/1889591/503621 và nhận xét
&
https://superuser.com/q/405097/47628
https://stackoverflow.com/a/5550502/503621


Environment.SpecialFolder.CommonApplicationData$(APPDATA)không cùng một thư mục
Sebastian Negraszus,

Bạn cũng có thể thử "$ {ALLUSERSPROFILE}" để thay thế. .
bshea

3

Để thay đổi đường dẫn của nhật ký lỗi (dựa trên câu trả lời của JackAce):

private static void SetLogPath(string path, string errorPath)
{
    XmlConfigurator.Configure();
    log4net.Repository.Hierarchy.Hierarchy h =
    (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository();
    foreach (var a in h.Root.Appenders)
    {
        if (a is log4net.Appender.FileAppender)
        {
            if (a.Name.Equals("LogFileAppender"))
            { 
                log4net.Appender.FileAppender fa = (log4net.Appender.FileAppender)a;                    
                string logFileLocation = path; 
                fa.File = logFileLocation;                   
                fa.ActivateOptions();
            }
            else if (a.Name.Equals("ErrorFileAppender"))
            {
                log4net.Appender.FileAppender fa = (log4net.Appender.FileAppender)a;
                string logFileLocation = errorPath;
                fa.File = logFileLocation;
                fa.ActivateOptions();
            }
        }
    }
}

3

Câu trả lời của JackAce, ngắn gọn hơn bằng cách sử dụng Linq:

C #

XmlConfigurator.Configure();
var appender = (LogManager.GetRepository() as Hierarchy).Root.Appenders
    .OfType<FileAppender>()
    .First();

appender.File = logPath;
appender.ActivateOptions();

VB.NET

XmlConfigurator.Configure()
Dim appender = CType(LogManager.GetRepository(), Hierarchy).Root.Appenders _
    .OfType(FileAppender)() _
    .First()

appender.File = logPath
appender.ActivateOptions()

2

Trường hợp sử dụng tuyệt vời cho OfType<T>bộ lọc LINQs :

/// <summary>
/// Applies a transformation to the filenames of all FileAppenders.
/// </summary>
public static void ChangeLogFile(Func<string,string> transformPath)
{
    // iterate over all FileAppenders
    foreach (var fileAppender in LogManager.GetRepository().GetAppenders().OfType<FileAppender>())
    {
        // apply transformation to the filename
        fileAppender.File = transformPath(fileAppender.File);
        // notify the logging subsystem of the configuration change
        fileAppender.ActivateOptions();
    }
}

Nếu tên tệp trong app.config là, log.txtđiều này sẽ thay đổi đầu ra nhật ký thành logs/some_name_log.txt:

ChangeLogFile(path => Path.Combine("logs", $"some_name_{Path.GetFileName(path)}"));

Để trả lời vấn đề ban đầu OPs sẽ là:

ChangeLogFile(path => Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), path));

Khi tôi làm điều này, nó chỉ đơn giản là tạo lại một tệp trống với tên mới, nhưng sau đó Logger.GetLoggertiếp tục ghi vào tên cũ thay thế.
Jay Sullivan

1

Để thay thế cho việc này theo chương trình, bạn có thể sử dụng các biến môi trường và các mẫu có thể tùy chỉnh trong tệp cấu hình. Xem câu trả lời này cho một câu hỏi tương tự .

Xem "Chuỗi mẫu cho cấu hình dựa trên mẫu" trong ghi chú phát hành Log4Net V1.2.10 .

Ngoài ra, nếu bạn đang nghĩ đến việc ghi vào một thư mục như Enviroment.SpecialFolder.CommonApplicationData, bạn cần xem xét:

  • Liệu tất cả các phiên bản ứng dụng của bạn dành cho tất cả người dùng có quyền ghi vào tệp nhật ký không? Ví dụ: Tôi không tin rằng những người không phải là quản trị viên sẽ có thể ghi vào Enviroment.SpecialFolder.CommonApplicationData.

  • Đề cập nếu nhiều trường hợp ứng dụng của bạn (cho cùng một hoặc nhiều người dùng khác nhau) đang cố gắng truy cập vào cùng một tệp. Bạn có thể sử dụng "mô hình khóa tối thiểu" (xemhttp://logging.apache.org/log4net/release/config-examples.html để cho phép nhiều quy trình ghi vào cùng một tệp nhật ký, nhưng có thể sẽ có tác động đến hiệu suất. Hoặc bạn có thể cung cấp cho mỗi quy trình một tệp nhật ký khác nhau, ví dụ: bằng cách bao gồm id quy trình trong tên tệp bằng cách sử dụng mẫu có thể tùy chỉnh.


1

Trong phiên bản hiện tại của Log4Net (2.0.8.0), bạn chỉ cần sử dụng <file value="${ProgramData}\myFolder\LogFiles\" />cho C:\ProgramData\..${LocalAppData}choC:\Users\user\AppData\Local\


0

Nếu bạn phải triển khai đến các hệ thống không xác định và bạn muốn sử dụng giải pháp đơn giản của Philipp M ngay cả với các thư mục đặc biệt khác nhau, bạn có thể truy xuất đường dẫn thư mục đặc biệt bạn muốn và đặt một biến env tùy chỉnh trước khi tải cấu hình log4net. string localData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); Environment.SetEnvironmentVariable("MY_FOLDER_DATA", localData); XmlConfigurator.Configure( ...

... chỉ để chắc chắn rằng biến env tồn tại và có giá trị bạn muốn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.