web-dev-qa-db-ja.com

プログラムでファイルの場所を変更するにはどうすればよいですか?

Log4netを初めて使用します。
設定ファイルと簡単なログを追加することで、なんとか成功しました。
値を"C:\temp\log.txt"にハードコーディングしましたが、これでは十分ではありません。

ログは特別なフォルダーに移動する必要があります

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

このパスは、Windows Server 2008またはWindows XPまたはVistaなど...

Log4netのファイルの場所をプログラムで変更するにはどうすればよいですか?

これは私がやったことです:

<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?
    }
}

必要な場所にログを記録するように変更する方法を理解する必要があります。

助言がありますか?どうもありがとう

71
user186134

log4netがこれを処理します。文字列型のアペンダープロパティは、この場合は log4net.Util.PatternString オプションハンドラーを使用してフォーマットできます。 PatternStringは SpecialFolder enumをサポートし、次のエレガントな設定を可能にします:

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

プリンを証明する単体テストは次のとおりです。

[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));
}

次のテストでは、log4netが実際にディスクに書き込むことを確認します(これにより、基本的にこれは単体テストではなく「統合」テストになりますが、今のところはそのままにします)。

[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"));
}

注意:上記のサンプルで示したコンパクトプロパティ構文を使用することを強くお勧めします。これらの「<property name =」をすべて削除すると、構成がより読みやすくなります。

86
Peter Lillevold

インターウェブでこのコードの変異を見つけました:

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;
    }
}

これは私のために動作します。アプリケーションは、AssemblyInfo.csファイルに基づいてアプリのバージョン番号を含むフォルダーにログファイルを配置する必要があります。

LogFileLocationをプログラムで設定できる必要があります(これがWebアプリケーションの場合、Server.MapPath()を使用できます)。

41
JackAce

Peter's answer はLog4net v1.2.10.0では機能しません。代替方法は here で説明されています。

基本的に、メソッドはlog4net構成ファイル用のカスタムパターンコンバーターを実装することです。

最初にこのクラスをプロジェクトに追加します。

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));
    }
}

次に、FileAppenderのFileパラメーターを次のように設定します。

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

基本的に、%folderは、SpecialFolderPatternConverterクラスを指すfolderというコンバーターを参照するように指示します。次に、そのクラスでConvertを呼び出し、CommonApplicationData(または何でも)列挙値を渡します。

14
codeulike

シンプルな方法はどうですか:

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

本当に簡単なことをするのはなぜそんなに複雑なのですか?

6
Eric

これは私のために働いた:

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

特別なフォルダーに書き込む必要がある場合、ヘルプを見つけました here (2番目と3番目の例)。

編集:

OPに答えるには、これは「すべてのユーザー」領域で機能します。

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

これは通常、Windowsの新しいバージョンでは「C:\ ProgramData」です。

これらも参照してください。
log4netの共通アプリケーションデータフォルダーの指定方法 == https://stackoverflow.com/a/1889591/503621 およびコメント

https://superuser.com/q/405097/47628
https://stackoverflow.com/a/5550502/503621

4
bshea

JackAceの答えは、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()
3
jmjohnson85

エラーログのパスも変更するには(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
Jim109

LINQの優れた使用例 OfType<T> フィルター:

/// <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();
    }
}

App.configのファイル名がlog.txtの場合、これはログ出力をlogs/some_name_log.txtに変更します。

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

OPの元の問題に答えるには:

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

Log4Netの現在のバージョン(2.0.8.0)では、単に<file value="${ProgramData}\myFolder\LogFiles\" /> ために C:\ProgramData\..および${LocalAppData} ために C:\Users\user\AppData\Local\

1
Apfelkuacha

プログラムでこれを行う代わりに、環境変数とカスタマイズ可能なパターンを構成ファイルで使用できます。 同様の質問に対するこの回答をご覧ください

Log4Net V1.2.10リリースノート の「パターンベースの構成のパターン文字列」を参照してください。

Enviroment.SpecialFolder.CommonApplicationDataなどのディレクトリへの書き込みを検討している場合も考慮する必要があります。

  • すべてのユーザーのアプリケーションのすべてのインスタンスに、ログファイルへの書き込みアクセス権がありますか?例えば。非管理者がEnviroment.SpecialFolder.CommonApplicationDataに書き込むことができるとは思わない。

  • アプリケーションの複数のインスタンス(同じユーザーまたは異なるユーザー)が同じファイルを試行している場合の競合。 「最小ロックモデル」を使用できます( http://logging.Apache.org/log4net/release/config-examples.html を参照して、複数のプロセスによる書き込みを許可します)または、カスタマイズ可能なパターンを使用してファイル名にプロセスIDを含めることにより、各プロセスに異なるログファイルを与えることができます。

0
Joe

未知のシステムにデプロイする必要があり、異なる特別なフォルダーがある場合でもPhilipp Mのシンプルなソリューションを使用する場合、log4net構成をロードする前に、必要な特別なフォルダーパスを取得し、カスタムenv変数を設定できます。 string localData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); Environment.SetEnvironmentVariable("MY_FOLDER_DATA", localData); XmlConfigurator.Configure( ...

... env変数が存在し、必要な値になっていることを確認するためだけです。

0
user3529289