Je suis totalement nouveau sur Log4net.
J'ai réussi à obtenir quelque chose en ajoutant un fichier de configuration et une simple journalisation.
J'ai codé en dur la valeur pour qu'elle soit "C:\temp\log.txt"
mais cela ne suffit pas.
Les journaux doivent aller dans les dossiers spéciaux
path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
et ce chemin change selon que vous utilisez Windows Server 2008 ou Windows XP ou Vista, etc.
Comment puis-je simplement modifier l'emplacement du fichier dans log4net par programme?
Voici ce que j'ai fait:
<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?
}
}
Juste besoin de comprendre comment je peux changer pour enregistrer les choses là où je veux.
Des suggestions? Merci beaucoup
log4net peut gérer cela pour vous. Toute propriété appender de type chaîne peut être formatée, dans ce cas, en utilisant le gestionnaire log4net.Util.PatternString option. PatternString supporte même le SpecialFolder enum qui permet la config élégante suivante:
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender" >
<file type="log4net.Util.PatternString"
value="%envFolderPath{CommonApplicationData}\\test.txt" />
...
</appender>
Voici un test unitaire qui vérifie le 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));
}
Le test suivant vérifie que log4net écrit réellement sur le disque (ce qui en fait fondamentalement un test "d'intégration", pas un test unitaire, mais nous en resterons là pour l'instant):
[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: Je suggère fortement d'utiliser la syntaxe de propriété compact démontrée dans l'exemple ci-dessus. Supprimer tous ces "<property name =" rend votre configuration encore plus lisible.
J'ai trouvé une mutation de ce code dans les interwebs:
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;
}
}
Cela fonctionne pour moi. Notre application doit placer le fichier journal dans un dossier contenant le numéro de version de l'application basé sur le fichier AssemblyInfo.cs.
Vous devriez pouvoir définir logFileLocation par programme (par exemple, vous pouvez utiliser Server.MapPath () s'il s'agit d'une application Web) pour répondre à vos besoins.
On dirait que la réponse de Peter ne fonctionne pas pour Log4net v1.2.10.0. Une méthode alternative est décrite ici .
Fondamentalement, la méthode consiste à implémenter un convertisseur de modèle personnalisé pour le fichier de configuration log4net.
Ajoutez d'abord cette classe à votre projet:
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));
}
}
Configurez ensuite le paramètre File de votre FileAppender comme suit:
<file type="log4net.Util.PatternString">
<converter>
<name value="folder" />
<type value="MyAppName.SpecialFolderPatternConverter,MyAppName" />
</converter>
<conversionPattern value="%folder{CommonApplicationData}\\SomeOtherFolder\\log.txt" />
</file>
En gros, le %folder
lui dit de regarder le convertisseur appelé folder
qui le dirige vers la classe SpecialFolderPatternConverter. Il appelle ensuite Convert
sur cette classe, en transmettant la valeur enum CommonApplicationData (ou autre).
Que diriez-vous d'un simple:
XmlConfigurator.LogFullFilename = @"c:\ProgramData\MyApp\Myapp.log";
Pourquoi est-ce si complexe de faire une chose très simple?
Cela a fonctionné pour moi:
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
..
<file value="${APPDATA}\MyApp\MyApp Client\logs\Log.txt"/>
..
</log4net>
Si j'ai besoin d'écrire dans des dossiers spéciaux, j'ai trouvé aide ici (2ème et 3ème exemple).
Modifier:
Pour répondre à OP .. Cela fonctionne pour la zone 'tous les utilisateurs':
...
<file value="${ALLUSERSPROFILE}\MyApp\MyApp Client\logs\Log.txt"/>
...
Ce qui correspond normalement à "C:\ProgramData" dans les versions les plus récentes de Windows.
Voir ces aussi:
Comment spécifier un dossier de données d'application commun pour log4net? == https://stackoverflow.com/a/1889591/503621 et commentaires
&
https://superuser.com/q/405097/47628
https://stackoverflow.com/a/5550502/503621
La réponse de JackAce, juste plus concise avec 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()
Pour modifier également le chemin du journal des erreurs (en fonction de la réponse de 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();
}
}
}
}
Dans la version actuelle de Log4Net (2.0.8.0), vous pouvez simplement utiliser <file value="${ProgramData}\myFolder\LogFiles\" />
pour C:\ProgramData\..
et ${LocalAppData}
pour C:\Users\user\AppData\Local\
Excellent cas d'utilisation pour LINQs OfType<T>
filter:
/// <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();
}
}
Si le nom de fichier dans app.config est log.txt
, la sortie du journal deviendra logs/some_name_log.txt
:
ChangeLogFile(path => Path.Combine("logs", $"some_name_{Path.GetFileName(path)}"));
Pour répondre au problème initial des PO, ce serait:
ChangeLogFile(path => Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), path));
Au lieu d'effectuer cette opération par programme, vous pouvez utiliser des variables d'environnement et des modèles personnalisables dans le fichier de configuration. Voir cette réponse à une question similaire .
Consultez la section "PatternString pour une configuration basée sur un modèle" dans les notes de publication de Log4Net V1.2.10 .
De même, si vous envisagez d'écrire dans un répertoire tel que Enviroment.SpecialFolder.CommonApplicationData, vous devez prendre en compte:
Toutes les instances de votre application pour tous les utilisateurs auront-elles un accès en écriture au fichier journal? Par exemple. Je ne crois pas que les non-administrateurs pourront écrire dans Enviroment.SpecialFolder.CommonApplicationData.
Conflit si plusieurs instances de votre application (pour le même utilisateur ou des utilisateurs différents) tentent de créer le même fichier. Vous pouvez utiliser le "modèle de verrouillage minimal" (voir http://logging.Apache.org/log4net/release/config-examples.html permettre à plusieurs processus d'écrire dans le même fichier journal, mais cela aura probablement un impact sur les performances. Ou vous pouvez attribuer à chaque processus un fichier journal différent, par exemple. en incluant l'identifiant de processus dans le nom du fichier en utilisant un modèle personnalisable.
Si vous devez déployer sur des systèmes inconnus et que vous voulez utiliser la solution simple de Philipp M même avec différents dossiers spéciaux, vous pouvez récupérer le chemin de dossier spécial souhaité et définir une variable d'environnement personnalisée avant de charger la configuration log4net .
string localData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
Environment.SetEnvironmentVariable("MY_FOLDER_DATA", localData);
XmlConfigurator.Configure( ...
... juste pour être sûr que la variable env existe et a la valeur que vous voulez.