//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Threading;
using System.Configuration;
using System.Security;
using System.Security.Permissions;
using System.Diagnostics.CodeAnalysis;
namespace System.Diagnostics {
public class TraceSource {
private static List tracesources = new List();
private static int s_LastCollectionCount;
private volatile SourceSwitch internalSwitch;
private volatile TraceListenerCollection listeners;
private StringDictionary attributes;
private SourceLevels switchLevel;
private volatile string sourceName;
internal volatile bool _initCalled = false; // Whether we've called Initialize already.
public TraceSource(string name)
: this(name, SourceLevels.Off) {
}
public TraceSource(string name, SourceLevels defaultLevel) {
if (name == null)
throw new ArgumentNullException("name");
if (name.Length == 0)
throw new ArgumentException("name");
sourceName = name;
switchLevel = defaultLevel;
// Delay load config to avoid perf (and working set) issues in retail
// Add a weakreference to this source and cleanup invalid references
lock(tracesources) {
_pruneCachedTraceSources();
tracesources.Add(new WeakReference(this));
}
}
private static void _pruneCachedTraceSources() {
lock (tracesources) {
if (s_LastCollectionCount != GC.CollectionCount(2)) {
List buffer = new List(tracesources.Count);
for (int i = 0; i < tracesources.Count; i++) {
TraceSource tracesource = ((TraceSource)tracesources[i].Target);
if (tracesource != null) {
buffer.Add(tracesources[i]);
}
}
if (buffer.Count < tracesources.Count) {
tracesources.Clear();
tracesources.AddRange(buffer);
tracesources.TrimExcess();
}
s_LastCollectionCount = GC.CollectionCount(2);
}
}
}
private void Initialize() {
if (!_initCalled) {
lock(this) {
if (_initCalled)
return;
#if CONFIGURATION_DEP
SourceElementsCollection sourceElements = DiagnosticsConfiguration.Sources;
if (sourceElements != null) {
SourceElement sourceElement = sourceElements[sourceName];
if (sourceElement != null) {
if (!String.IsNullOrEmpty(sourceElement.SwitchName)) {
CreateSwitch(sourceElement.SwitchType, sourceElement.SwitchName);
}
else {
CreateSwitch(sourceElement.SwitchType, sourceName);
if (!String.IsNullOrEmpty(sourceElement.SwitchValue))
internalSwitch.Level = (SourceLevels) Enum.Parse(typeof(SourceLevels), sourceElement.SwitchValue);
}
listeners = sourceElement.Listeners.GetRuntimeObject();
attributes = new StringDictionary();
TraceUtils.VerifyAttributes(sourceElement.Attributes, GetSupportedAttributes(), this);
attributes.ReplaceHashtable(sourceElement.Attributes);
}
else
NoConfigInit();
}
else
#endif
NoConfigInit();
_initCalled = true;
}
}
}
private void NoConfigInit() {
internalSwitch = new SourceSwitch(sourceName, switchLevel.ToString());
listeners = new TraceListenerCollection();
listeners.Add(new DefaultTraceListener());
attributes = null;
}
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
public void Close() {
// No need to call Initialize()
if (listeners != null) {
// Use global lock
lock (TraceInternal.critSec) {
foreach (TraceListener listener in listeners) {
listener.Close();
}
}
}
}
public void Flush() {
// No need to call Initialize()
if (listeners != null) {
if (TraceInternal.UseGlobalLock) {
lock (TraceInternal.critSec) {
foreach (TraceListener listener in listeners) {
listener.Flush();
}
}
}
else {
foreach (TraceListener listener in listeners) {
if (!listener.IsThreadSafe) {
lock (listener) {
listener.Flush();
}
}
else {
listener.Flush();
}
}
}
}
}
virtual protected internal string[] GetSupportedAttributes() {
return null;
}
internal static void RefreshAll() {
lock (tracesources) {
_pruneCachedTraceSources();
for (int i=0; i