1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.Core
.Logging
20 using System
.Diagnostics
;
21 using System
.Collections
.Generic
;
24 /// The TraceLogger sends all logging to the System.Diagnostics.TraceSource
25 /// built into the .net framework.
28 /// Logging can be configured in the system.diagnostics configuration
31 /// If logger doesn't find a source name with a full match it will
32 /// use source names which match the namespace partially. For example you can
33 /// configure from all castle components by adding a source name with the
36 /// If no portion of the namespace matches the source named "Default" will
39 public class TraceLogger
: LevelFilteredLogger
41 private static readonly Dictionary
<string, TraceSource
> cache
= new Dictionary
<string, TraceSource
>();
43 TraceSource traceSource
;
46 /// Build a new trace logger based on the named TraceSource
48 /// <param name="name">The name used to locate the best TraceSource. In most cases comes from the using type's fullname.</param>
49 public TraceLogger(string name
)
53 Level
= MapLoggerLevel(traceSource
.Switch
.Level
);
57 /// Build a new trace logger based on the named TraceSource
59 /// <param name="name">The name used to locate the best TraceSource. In most cases comes from the using type's fullname.</param>
60 /// <param name="level">The default logging level at which this source should write messages. In almost all cases this
61 /// default value will be overridden in the config file. </param>
62 public TraceLogger(string name
, LoggerLevel level
)
66 Level
= MapLoggerLevel(traceSource
.Switch
.Level
);
70 /// Create a new child logger.
71 /// The name of the child logger is [current-loggers-name].[passed-in-name]
73 /// <param name="name">The Subname of this logger.</param>
74 /// <returns>The New ILogger instance.</returns>
75 public override ILogger
CreateChildLogger(string name
)
77 return new TraceLogger(string.Concat(Name
, ".", name
), Level
);
80 protected override void Log(LoggerLevel level
, string name
, string message
, Exception exception
)
82 if (exception
== null)
84 traceSource
.TraceEvent(MapTraceEventType(level
), 0, message
);
88 traceSource
.TraceData(MapTraceEventType(level
), 0, message
, exception
);
96 // because TraceSource is meant to be used as a static member, and because
97 // building up the configuraion inheritance is non-trivial, the instances
98 // themselves are cached for so multiple TraceLogger instances will reuse
99 // the named TraceSources which have been created
101 if (cache
.TryGetValue(Name
, out traceSource
))
105 SourceLevels defaultLevel
= MapSourceLevels(Level
);
106 traceSource
= new TraceSource(Name
, defaultLevel
);
108 // no further action necessary when the named source is configured
109 if (IsSourceConfigured(traceSource
))
111 cache
.Add(Name
, traceSource
);
115 // otherwise hunt for a shorter source that been configured
116 TraceSource foundSource
= new TraceSource("Default", defaultLevel
);
118 string searchName
= ShortenName(Name
);
119 while (!string.IsNullOrEmpty(searchName
))
121 TraceSource searchSource
= new TraceSource(searchName
, defaultLevel
);
122 if (IsSourceConfigured(searchSource
))
124 foundSource
= searchSource
;
128 searchName
= ShortenName(searchName
);
131 // reconfigure the created source to act like the found source
132 traceSource
.Switch
= foundSource
.Switch
;
133 traceSource
.Listeners
.Clear();
134 foreach (TraceListener listener
in foundSource
.Listeners
)
135 traceSource
.Listeners
.Add(listener
);
137 cache
.Add(Name
, traceSource
);
141 static string ShortenName(string name
)
143 int lastDot
= name
.LastIndexOf('.');
146 return name
.Substring(0, lastDot
);
152 static bool IsSourceConfigured(TraceSource source
)
154 if (source
.Listeners
.Count
== 1 &&
155 source
.Listeners
[0] is DefaultTraceListener
&&
156 source
.Listeners
[0].Name
== "Default")
164 static LoggerLevel
MapLoggerLevel(SourceLevels level
)
168 case SourceLevels
.All
:
169 return LoggerLevel
.Debug
;
170 case SourceLevels
.Verbose
:
171 return LoggerLevel
.Debug
;
172 case SourceLevels
.Information
:
173 return LoggerLevel
.Info
;
174 case SourceLevels
.Warning
:
175 return LoggerLevel
.Warn
;
176 case SourceLevels
.Error
:
177 return LoggerLevel
.Error
;
178 case SourceLevels
.Critical
:
179 return LoggerLevel
.Fatal
;
181 return LoggerLevel
.Off
;
184 static SourceLevels
MapSourceLevels(LoggerLevel level
)
188 case LoggerLevel
.Debug
:
189 return SourceLevels
.Verbose
;
190 case LoggerLevel
.Info
:
191 return SourceLevels
.Information
;
192 case LoggerLevel
.Warn
:
193 return SourceLevels
.Warning
;
194 case LoggerLevel
.Error
:
195 return SourceLevels
.Error
;
196 case LoggerLevel
.Fatal
:
197 return SourceLevels
.Critical
;
199 return SourceLevels
.Off
;
202 static TraceEventType
MapTraceEventType(LoggerLevel level
)
206 case LoggerLevel
.Debug
:
207 return TraceEventType
.Verbose
;
208 case LoggerLevel
.Info
:
209 return TraceEventType
.Information
;
210 case LoggerLevel
.Warn
:
211 return TraceEventType
.Warning
;
212 case LoggerLevel
.Error
:
213 return TraceEventType
.Error
;
214 case LoggerLevel
.Fatal
:
215 return TraceEventType
.Critical
;
217 return TraceEventType
.Verbose
;