2016-03-05 61 views
2

对于MVC应用程序定制的监听器不创建日志文件时所采用initializeData =“CustomWeblog.txt”参数,但initializeData =“d:\ CustomWeblog.txt”触发器文件创建。这种行为的原因是什么?控制台应用程序为所有类型的监听器生成文件。Asp.NET MVC,自TextWriterTraceListener会不会创建一个文件

自定义类:

public class CustomTextWriterTraceListener : TextWriterTraceListener 
{ 
    public CustomTextWriterTraceListener(string fileName) : base(fileName) 
} 

的Web.config(MVC应用程序的web.config)

<trace autoflush="true" /> 
<sources> 
    <source name="Trace">  
     <listeners> 
     <add name="TextWriterListner" 
      type="System.Diagnostics.TextWriterTraceListener, WebTracing" initializeData="Weblog.txt"/> 
     <!-- the file is created --> 
     <add name="CustomTextWriterListner" 
      type="WebTracing.CustomTextWriterTraceListener, WebTracing" initializeData="CustomWeblog.txt"/> 
     <!-- the file is not created in MVC application ?! --> 
     <add name="CustomTextWriterListnerAbsolutePath" 
      type="WebTracing.CustomTextWriterTraceListener, WebTracing" initializeData="d:\CustomWeblog.txt"/> 
     <!-- the file is created --> 
     </listeners>  
    </source> 
</sources> 

对自定义监听器不创建日志文件。

来电:

TraceSource obj = new TraceSource("Trace", SourceLevels.All); 
obj.TraceEvent(TraceEventType.Critical,0,"This is a critical message"); 

我尝试添加一些额外的配置:从this blogthis one。但没有成功。我应该提供一条绝对路径吗?是否有任何解决方法通过为自定义侦听器创建单独的程序集?

+1

有一个类似的问题。如果你检查你的事件日志,你可能会看到与iis相关的错误。通常,该进程没有权限在站点根目录中创建日志文件。如果'initializeData =“CustomWeblog.txt”' – Nkosi

+1

'catch(UnauthorisedAccessException){break; }'在新的StreamWriter(...)'构造函数调用时被触发.. – Spirit

+1

这是正确的。我必须查看原始源代码才能看到发生了什么,所以我在自定义侦听器中也做了同样的事情。我将发布我如何解决这个问题的代码。 – Nkosi

回答

2

当我遇到同样的问题时,我试图创建自己的滚动文本编写器跟踪侦听器。长话短说,毕竟这里跑来跑去是我想出来的。

public class RollingTextWriterTraceListener : TextWriterTraceListener { 
    string fileName; 
    private static string[] _supportedAttributes = new string[] 
     { 
      "template", "Template", 
      "convertWriteToEvent", "ConvertWriteToEvent", 
      "addtoarchive","addToArchive","AddToArchive", 
     }; 

    public RollingTextWriterTraceListener(string fileName) 
     : base() { 
     this.fileName = fileName; 
    } 
    /// <summary> 
    /// This makes sure that the writer exists to be written to. 
    /// </summary> 
    private void ensureWriter() { 
     //Resolve file name given. relative paths (if present) are resolved to full paths. 
     // Also allows for paths like this: initializeData="~/Logs/{ApplicationName}_{DateTime:yyyy-MM-dd}.log" 
     var logFileFullPath = ServerPathUtility.ResolvePhysicalPath(fileName); 
     var writer = base.Writer; 
     if (writer == null && createWriter(logFileFullPath)) { 
      writer = base.Writer; 
     } 
     if (!File.Exists(logFileFullPath)) { 
      if (writer != null) { 
       try { 
        writer.Flush(); 
        writer.Close(); 
        writer.Dispose(); 
       } catch (ObjectDisposedException) { } 
      } 
      createWriter(logFileFullPath); 
     } 
     //Custom code to package the previous log file(s) into a zip file. 
     if (AddToArchive) { 
      TextFileArchiveHelper.Archive(logFileFullPath); 
     } 
    } 

    bool createWriter(string logFileFullPath) { 
     try { 
      logFileFullPath = ServerPathUtility.ResolveOrCreatePath(logFileFullPath); 
      var writer = new StreamWriter(logFileFullPath, true); 
      base.Writer = writer; 
      return true; 
     } catch (IOException) { 
      //locked as already in use 
      return false; 
     } catch (UnauthorizedAccessException) { 
      //ERROR_ACCESS_DENIED, mostly ACL issues 
      return false; 
     } 
    } 

    /// <summary> 
    /// Get the add to archive flag 
    /// </summary> 
    public bool AddToArchive { 
     get { 
      // Default behaviour is not to add to archive. 
      var addToArchive = false; 
      var key = Attributes.Keys.Cast<string>(). 
       FirstOrDefault(s => string.Equals(s, "addtoarchive", StringComparison.InvariantCultureIgnoreCase)); 
      if (!string.IsNullOrWhiteSpace(key)) { 
       bool.TryParse(Attributes[key], out addToArchive); 
      } 
      return addToArchive; 
     } 
    } 

    #region Overrides 
    /// <summary> 
    /// Allowed attributes for this trace listener. 
    /// </summary> 
    protected override string[] GetSupportedAttributes() { 
     return _supportedAttributes; 
    } 

    public override void Flush() { 
     ensureWriter(); 
     base.Flush(); 
    } 

    public override void Write(string message) { 
     ensureWriter(); 
     base.Write(message); 
    } 

    public override void WriteLine(string message) { 
     ensureWriter(); 
     base.WriteLine(message); 
    } 
    #endregion 
} 

UPDATE:这里是实用工具类,我写了解决的路径。

public static class ServerPathUtility { 

    public static string ResolveOrCreatePath(string pathToReplace) { 
     string rootedFileName = ResolvePhysicalPath(pathToReplace); 
     FileInfo fi = new FileInfo(rootedFileName); 
     try { 
      DirectoryInfo di = new DirectoryInfo(fi.DirectoryName); 
      if (!di.Exists) { 
       di.Create(); 
      } 
      if (!fi.Exists) { 
       fi.CreateText().Close(); 
      } 
     } catch { 
      // NO-OP 
      // TODO: Review what should be done here. 
     } 
     return fi.FullName; 
    } 

    public static string ResolvePhysicalPath(string pathToReplace) { 
     string rootedPath = ResolveFormat(pathToReplace); 
     if (rootedPath.StartsWith("~") || rootedPath.StartsWith("/")) { 
      rootedPath = System.Web.Hosting.HostingEnvironment.MapPath(rootedPath); 
     } else if (!Path.IsPathRooted(rootedPath)) { 
      rootedPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, rootedPath); 
     } 
     return rootedPath; 
    } 

    public static string ResolveFormat(string format) { 
     string result = format; 

     try { 
      result = ExpandApplicationVariables(format); 
     } catch (System.Security.SecurityException) { 
      // Log? 
     } 

     try { 
      string variables = Environment.ExpandEnvironmentVariables(result); 
      // If an Environment Variable is not found then remove any invalid tokens 
      Regex filter = new Regex("%(.*?)%", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); 

      string filePath = filter.Replace(variables, ""); 

      if (Path.GetDirectoryName(filePath) == null) { 
       filePath = Path.GetFileName(filePath); 
      } 
      result = filePath; 
     } catch (System.Security.SecurityException) { 
      // Log? 
     } 

     return result; 
    } 

    public static string ExpandApplicationVariables(string input) { 
     var filter = new Regex("{(.*?)}", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); 
     var result = filter.Replace(input, evaluateMatch()); 
     return result; 
    } 

    private static MatchEvaluator evaluateMatch() { 
     return match => { 
      var variableName = match.Value; 
      var value = GetApplicationVariable(variableName); 
      return value; 
     }; 
    } 

    public static string GetApplicationVariable(string variable) { 
     string value = string.Empty; 
     variable = variable.Replace("{", "").Replace("}", ""); 
     var parts = variable.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); 
     variable = parts[0]; 
     var parameter = string.Empty; 
     if (parts.Length > 1) { 
      parameter = string.Join("", parts.Skip(1)); 
     } 

     Func<string, string> resolve = null; 
     value = VariableResolutionStrategies.TryGetValue(variable.ToUpperInvariant(), out resolve) && resolve != null 
      ? resolve(parameter) 
      : string.Empty; 

     return value; 
    } 

    public static readonly IDictionary<string, Func<string, string>> VariableResolutionStrategies = 
     new Dictionary<string, Func<string, string>> { 
      {"MACHINENAME", p => Environment.MachineName }, 
      {"APPDOMAIN", p => AppDomain.CurrentDomain.FriendlyName }, 
      {"DATETIME", getDate}, 
      {"DATE", getDate}, 
      {"UTCDATETIME", getUtcDate}, 
      {"UTCDATE", getUtcDate}, 
     }; 

    static string getDate(string format = "yyyy-MM-dd") { 
     var value = string.Empty; 
     if (string.IsNullOrWhiteSpace(format)) 
      format = "yyyy-MM-dd"; 
     value = DateTime.Now.ToString(format); 
     return value; 
    } 

    static string getUtcDate(string format = "yyyy-MM-dd") { 
     var value = string.Empty; 
     if (string.IsNullOrWhiteSpace(format)) 
      format = "yyyy-MM-dd"; 
     value = DateTime.Now.ToString(format); 
     return value; 
    } 
} 

所以这个工具类让我来解决相对路径和还可以自定义格式。例如,如果你看一下代码,你会看到,应用程序的名称ApplicationName变量没有在这个路径中

"~/Logs/{ApplicationName}_{DateTime:yyyy-MM-dd}.log" 

我能够配置在应用程序的启动与任何其他变量我想沿添加像这样

public partial class Startup { 
    public void Configuration(IAppBuilder app) { 
     //... Code removed for brevity   
     // Add APPLICATIONNAME name to path Utility 
     ServerPathUtility.VariableResolutionStrategies["APPLICATIONNAME"] = p => { 
      var assembly = System.Reflection.Assembly.GetExecutingAssembly(); 
      if (assembly != null) 
       return assembly.GetName().Name; 
      return string.Empty; 
     };   
    } 
} 
+0

是否可以添加ServerPathUtility.ResolveOrCreatePath方法?如何处理initializeData =“〜/ Logs/{ApplicationName} _ {DateTime:yyyy-MM-dd} .log”参数(相对路径和模板)非常有趣。 – Spirit

2

好了,终于,我已改用调查生成监听路径的方式。我在调试时注意到,源侦听器列表包含不同的路径。

  • System.Diagnostics.TextWriterTraceListener侦听器对象具有生成的完整路径;
  • WebTracing.CustomTextWriterTraceListener只有文件名。没有生成的错误。

由于自定义侦听的原因导致的不同值导致UnauthorisedAccessException异常,以便应用程序在不通知我们有关权限问题的情况下继续工作。

但什么是存储自定义监听器日志文件的地方吗?是否生成 ?

以下指向TextWriterTraceListener source code的链接帮助我找出路径。下面的代码:

//initializeData="CustomWeblog.txt", so fileName == "CustomWeblog.txt" here 
string fullPath = Path.GetFullPath(fileName); 
string dirPath = Path.GetDirectoryName(fullPath); 
string fileNameOnly = Path.GetFileName(fullPath); 

实际存储路径取决于项目>属性>网络>服务器:IIS快递:

C:\ Program Files文件(x86)的\ IIS快递\ CustomWeblog.txt

我一直在使用MVC应用程序(作为管理员:vs以管理员身份运行)在该文件夹中正确生成了日志文件。当我在没有管理员权限的情况下运行VS时,自定义侦听器根本不会创建文件。

正如上面所说,我执行了源代码监听器,发现catch(UnauthorisedAccessException) { break; }是在构造函数调用new StreamWriter(...)上触发的。


作为另一变通方法,您可以在initializeData="d:\CustomWeblog.txt"属性声明的完整路径。但请记住,您必须拥有适当的权限。