void IActivityMonitorClient.OnAutoTagsChanged(CKTrait newTags) { if (_pushTopicAndAutoTagsToTarget) { _bridgeTarget.SetAutoTags(newTags); } }
internal ActivityLogGroupConclusion(CKTrait t, string conclusion) { Debug.Assert(t != null && t.Context == ActivityMonitor.Tags.Context); Debug.Assert(conclusion != null); Tag = t; Text = conclusion; }
void DoSetAutoTags(CKTrait newTags) { Debug.Assert(_enteredThreadId == Thread.CurrentThread.ManagedThreadId); Debug.Assert(newTags != null && _currentTag != newTags && newTags.Context == Tags.Context); _currentTag = newTags; _output.BridgeTarget.TargetAutoTagsChanged(newTags); MonoParameterSafeCall((client, tags) => client.OnAutoTagsChanged(tags), newTags); }
CKTraitContext(string name, char separator, bool shared, ICKBinaryReader r) { if (String.IsNullOrWhiteSpace(name)) { throw new ArgumentException(Core.Impl.CoreResources.ArgumentMustNotBeNullOrWhiteSpace, "uniqueName"); } Name = name.Normalize(); Separator = separator; if (!shared) { Monitor.Enter(_basicLock); } var found = _regexes.FirstOrDefault(reg => reg.Key[0] == separator); if (found.Key == null) { _separatorString = new String(separator, 1); string pattern = "(\\s*" + Regex.Escape(_separatorString) + "\\s*)+"; _canonize2 = new Regex(pattern, RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.CultureInvariant); _regexes.Add(new KeyValuePair <string, Regex>(_separatorString, _canonize2)); } else { _separatorString = found.Key; _canonize2 = found.Value; } if (!shared) { Monitor.Exit(_basicLock); } EmptyTrait = new CKTrait(this); if (r != null) { IEnumerable <KeyValuePair <string, CKTrait> > Read() { yield return(new KeyValuePair <string, CKTrait>(String.Empty, EmptyTrait)); int count = r.ReadInt32(); for (int i = 0; i < count; ++i) { var s = r.ReadString(); yield return(new KeyValuePair <string, CKTrait>(s, new CKTrait(this, s))); } } _tags = new ConcurrentDictionary <string, CKTrait>(Read(), StringComparer.Ordinal); } else { _tags = new ConcurrentDictionary <string, CKTrait>(StringComparer.Ordinal); _tags[String.Empty] = EmptyTrait; } EnumWithEmpty = new CKTrait[] { EmptyTrait }; _creationLock = new Object(); _independentIndex = shared ? 0 : Interlocked.Increment(ref _nextIndependentIndex); }
/// <summary> /// Initializes a new <see cref="ActivityMonitorLogData"/>. /// </summary> /// <param name="level">Log level. Can not be <see cref="LogLevel.None"/>.</param> /// <param name="exception">Exception of the log. Can be null.</param> /// <param name="tags">Tags (from <see cref="ActivityMonitor.Tags"/>) to associate to the log. It will be union-ed with the current <see cref="IActivityMonitor.AutoTags"/>.</param> /// <param name="text">Text of the log. Can be null or empty only if <paramref name="exception"/> is not null: the <see cref="T:Exception.Message"/> is the text.</param> /// <param name="logTime"> /// Time of the log. /// You can use <see cref="DateTimeStamp.UtcNow"/> or <see cref="ActivityMonitorExtension.NextLogTime">IActivityMonitor.NextLogTime()</see> extension method. /// </param> /// <param name="fileName">Name of the source file that emitted the log. Can be null.</param> /// <param name="lineNumber">Line number in the source file that emitted the log. Can be null.</param> public ActivityMonitorLogData(LogLevel level, Exception exception, CKTrait tags, string text, DateTimeStamp logTime, string fileName, int lineNumber) : this(level, fileName, lineNumber) { if (MaskedLevel == LogLevel.None || MaskedLevel == LogLevel.Mask) { throw new ArgumentException(Impl.ActivityMonitorResources.ActivityMonitorInvalidLogLevel, "level"); } Initialize(text, exception, tags, logTime); }
internal Entry(CKTrait tags, LogLevel level, string text, DateTimeStamp logTime, Exception ex) { Debug.Assert((level & LogLevel.IsFiltered) == 0); Tags = tags; MaskedLevel = level; LogTime = logTime; Text = text; Exception = ex; }
/// <summary> /// Sends a text obtained through a delegate with an exception and associated tags. /// The delegate will be called only if the log is not filtered. /// </summary> /// <param name="this">This <see cref="IActivityMonitorLineSender"/> object.</param> /// <param name="ex">The exception. Must not be null.</param> /// <param name="tags">Tags for the log.</param> /// <param name="text">Function that returns a string. Must not be null.</param> public static void Send(this IActivityMonitorLineSender @this, Exception ex, CKTrait tags, Func <string> text) { ActivityMonitorLineSender s = (ActivityMonitorLineSender)@this; if (s.IsRejected) { return; } s.InitializeAndSend(ex, tags, text == null ? null : text()); }
/// <summary> /// Sends a formatted text with an exception and associated tags. /// </summary> /// <param name="this">This <see cref="IActivityMonitorLineSender"/> object.</param> /// <param name="ex">The exception. Must not be null.</param> /// <param name="tags">Tags for the log.</param> /// <param name="format">The text format of the log with 4 placeholders.</param> /// <param name="arguments">Multiple parameters to format.</param> static public void Send(this IActivityMonitorLineSender @this, Exception ex, CKTrait tags, string format, params object[] arguments) { ActivityMonitorLineSender s = (ActivityMonitorLineSender)@this; if (s.IsRejected) { return; } s.InitializeAndSend(ex, tags, format == null ? null : String.Format(format, arguments)); }
/// <summary> /// Sends a text with an exception and associated tags. /// </summary> /// <param name="this">This <see cref="IActivityMonitorLineSender"/> object.</param> /// <param name="ex">The exception. Must not be null.</param> /// <param name="tags">Tags for the log.</param> /// <param name="text">The text of the log.</param> static public void Send(this IActivityMonitorLineSender @this, Exception ex, CKTrait tags, string text) { ActivityMonitorLineSender s = (ActivityMonitorLineSender)@this; if (s.IsRejected) { return; } s.InitializeAndSend(ex, tags, text); }
/// <summary> /// Sends a log with a text obtained through a parameterized delegate with associated tags. /// The delegate will be called only if the log is not filtered. /// </summary> /// <typeparam name="T1">Type of the first parameter that <paramref name="text"/> accepts.</typeparam> /// <typeparam name="T2">Type of the second parameter that <paramref name="text"/> accepts.</typeparam> /// <typeparam name="T3">Type of the third parameter that <paramref name="text"/> accepts.</typeparam> /// <param name="this">This <see cref="IActivityMonitorLineSender"/> object.</param> /// <param name="tags">Tags for the log.</param> /// <param name="text">Function that returns a string. Must not be null.</param> /// <param name="param1">First parameter for the <paramref name="text"/> delegate.</param> /// <param name="param2">Second parameter for the <paramref name="text"/> delegate.</param> /// <param name="param3">Third parameter for the <paramref name="text"/> delegate.</param> public static void Send <T1, T2, T3>(this IActivityMonitorLineSender @this, CKTrait tags, Func <T1, T2, T3, string> text, T1 param1, T2 param2, T3 param3) { ActivityMonitorLineSender s = (ActivityMonitorLineSender)@this; if (s.IsRejected) { return; } s.InitializeAndSend(null, tags, text == null ? null : text(param1, param2, param3)); }
/// <summary> /// Sends a formatted text with associated tags. /// </summary> /// <param name="this">This <see cref="IActivityMonitorLineSender"/> object.</param> /// <param name="tags">Tags for the log.</param> /// <param name="format">The text format of the log with 3 placeholders.</param> /// <param name="arg0">Parameter to format (placeholder {0}).</param> /// <param name="arg1">Parameter to format (placeholder {1}).</param> /// <param name="arg2">Parameter to format (placeholder {2}).</param> static public void Send(this IActivityMonitorLineSender @this, CKTrait tags, string format, object arg0, object arg1, object arg2) { ActivityMonitorLineSender s = (ActivityMonitorLineSender)@this; if (s.IsRejected) { return; } s.InitializeAndSend(null, tags, format == null ? null : String.Format(format, arg0, arg1, arg2)); }
/// <summary> /// Sends a text with associated tags. /// </summary> /// <param name="this">This <see cref="IActivityMonitorGroupSender"/> object.</param> /// <param name="tags">Tags for the log.</param> /// <param name="text">The text of the log.</param> static public IDisposableGroup Send(this IActivityMonitorGroupSender @this, CKTrait tags, string text) { ActivityMonitorGroupSender s = (ActivityMonitorGroupSender)@this; if (s.IsRejected) { return(s.Monitor.UnfilteredOpenGroup(s)); } return(s.InitializeAndSend(null, tags, text)); }
internal void TargetAutoTagsChanged(CKTrait newTags) { foreach (var b in _callbacks) { if (b.PullTopicAndAutoTagsFromTarget) { b.OnTargetAutoTagsChanged(newTags); } } }
/// <summary> /// Sends a formatted text with associated tags. /// </summary> /// <param name="this">This <see cref="IActivityMonitorGroupSender"/> object.</param> /// <param name="tags">Tags for the log.</param> /// <param name="format">The text format of the log with 5 placeholders.</param> /// <param name="arguments">Multiple parameters to format.</param> static public IDisposableGroup Send(this IActivityMonitorGroupSender @this, CKTrait tags, string format, params object[] arguments) { ActivityMonitorGroupSender s = (ActivityMonitorGroupSender)@this; if (s.IsRejected) { return(s.Monitor.UnfilteredOpenGroup(s)); } return(s.InitializeAndSend(null, tags, format == null ? null : String.Format(format, arguments))); }
static Tags() { Context = new CKTraitContext("ActivityMonitor"); Empty = Context.EmptyTrait; UserConclusion = Context.FindOrCreate("c:User"); GetTextConclusion = Context.FindOrCreate("c:GetText"); MonitorTopicChanged = Context.FindOrCreate("MonitorTopicChanged"); CreateDependentActivity = Context.FindOrCreate("dep:CreateActivity"); StartDependentActivity = Context.FindOrCreate("dep:StartActivity"); }
/// <summary> /// Initializes this data. /// </summary> /// <param name="text"> /// Text of the log. Can be null or empty: if <paramref name="exception"/> is not null, /// the <see cref="Exception.Message"/> becomes the text otherwise <see cref="ActivityMonitor.NoLogText"/> is used. /// </param> /// <param name="exception">Exception of the log. Can be null.</param> /// <param name="tags"> /// Tags (from <see cref="ActivityMonitor.Tags"/>) to associate to the log. /// It will be union-ed with the current <see cref="IActivityMonitor.AutoTags"/>.</param> /// <param name="logTime"> /// Time of the log. /// You can use <see cref="DateTimeStamp.UtcNow"/> or <see cref="ActivityMonitorExtension.NextLogTime">IActivityMonitor.NextLogTime()</see> extension method. /// </param> public void Initialize(string text, Exception exception, CKTrait tags, DateTimeStamp logTime) { if (string.IsNullOrEmpty((_text = text))) { _text = exception == null ? ActivityMonitor.NoLogText : exception.Message; } _exception = exception; _tags = tags ?? ActivityMonitor.Tags.Empty; _logTime = logTime; }
/// <summary> /// Initializes a new <see cref="ActivityMonitorTextWriterClient"/> bound to a /// function that must write a string, with a filter. /// </summary> /// <param name="writer">Function that writes the content.</param> /// <param name="filter">Filter to apply</param> public ActivityMonitorTextWriterClient(Action <string> writer, LogFilter filter) : base(filter) { if (writer == null) { throw new ArgumentNullException("writer"); } _writer = writer; _buffer = new StringBuilder(); _prefixLevel = _prefix = String.Empty; _currentTags = ActivityMonitor.Tags.Empty; }
CKTrait FindOrCreate(string traits, bool create) { if (traits == null || traits.Length == 0) { return(_empty); } traits = traits.Normalize(); if (traits.IndexOfAny(new[] { '\n', '\r' }) >= 0) { throw new ArgumentException(Impl.CoreResources.TraitsMustNotBeMultiLineString); } CKTrait m; if (!_traits.TryGetValue(traits, out m)) { int traitCount; string[] splitTraits = SplitMultiTrait(traits, out traitCount); if (traitCount <= 0) { return(_empty); } if (traitCount == 1) { m = FindOrCreateAtomicTrait(splitTraits[0], create); } else { traits = String.Join(_separatorString, splitTraits, 0, traitCount); if (!_traits.TryGetValue(traits, out m)) { CKTrait[] atomics = new CKTrait[traitCount]; for (int i = 0; i < traitCount; ++i) { CKTrait trait = FindOrCreateAtomicTrait(splitTraits[i], create); if ((atomics[i] = trait) == null) { return(null); } } lock ( _creationLock ) { if (!_traits.TryGetValue(traits, out m)) { m = new CKTrait(this, traits, atomics); _traits[traits] = m; } } } Debug.Assert(!m.IsAtomic && m.AtomicTraits.Count == traitCount, "Combined trait."); } } return(m); }
internal DateTimeStamp CombineTagsAndAdjustLogTime(CKTrait tags, DateTimeStamp lastLogTime) { if (_tags.IsEmpty) { _tags = tags; } else { _tags = _tags.Union(tags); } return(_logTime = new DateTimeStamp(lastLogTime, _logTime.IsKnown ? _logTime : DateTimeStamp.UtcNow)); }
/// <summary> /// Called by IActivityMonitorBoundClient clients to initialize Topic and AutoTag from /// inside their SetMonitor or any other methods provided that a reentrant and concurrent lock /// has been obtained (otherwise an InvalidOperationException is thrown). /// </summary> void IActivityMonitorImpl.InitializeTopicAndAutoTags(string newTopic, CKTrait newTags, string fileName, int lineNumber) { RentrantOnlyCheck(); if (newTopic != null && _topic != newTopic) { DoSetTopic(newTopic, fileName, lineNumber); } if (newTags != null && _currentTag != newTags) { DoSetAutoTags(newTags); } }
/// <summary> /// Sends a formatted text with associated tags. /// </summary> /// <param name="this">This <see cref="IActivityMonitorGroupSender"/> object.</param> /// <param name="tags">Tags for the log.</param> /// <param name="format">The text format of the log with 1 placeholders.</param> /// <param name="arg0">Parameter to format (placeholder {0}).</param> static public IDisposableGroup Send(this IActivityMonitorGroupSender @this, CKTrait tags, string format, object arg0) { ActivityMonitorGroupSender s = (ActivityMonitorGroupSender)@this; if (s.IsRejected) { return(s.Monitor.UnfilteredOpenGroup(s)); } if (arg0 is Exception) { throw new ArgumentException(Impl.ActivityMonitorResources.PossibleWrongOverloadUseWithException, "arg0"); } return(s.InitializeAndSend(null, tags, format == null ? null : String.Format(format, arg0))); }
/// <summary> /// Sends a formatted text with associated tags. /// </summary> /// <param name="this">This <see cref="IActivityMonitorLineSender"/> object.</param> /// <param name="tags">Tags for the log.</param> /// <param name="format">The text format of the log with 1 placeholders.</param> /// <param name="arg0">Parameter to format (placeholder {0}).</param> static public void Send(this IActivityMonitorLineSender @this, CKTrait tags, string format, object arg0) { ActivityMonitorLineSender s = (ActivityMonitorLineSender)@this; if (s.IsRejected) { return; } if (arg0 is Exception) { throw new ArgumentException(Impl.ActivityMonitorResources.PossibleWrongOverloadUseWithException, "arg0"); } s.InitializeAndSend(null, tags, format == null ? null : String.Format(format, arg0)); }
/// <summary> /// Initializes a new conclusion for a group. /// </summary> /// <param name="conclusion">Must not be null (may be empty).</param> /// <param name="tag">Must be null or be registered in <see cref="ActivityMonitor.Tags"/>.</param> public ActivityLogGroupConclusion(string conclusion, CKTrait tag = null) { if (conclusion == null) { throw new ArgumentNullException("conclusion"); } if (tag == null) { tag = ActivityMonitor.Tags.Empty; } else if (tag.Context != ActivityMonitor.Tags.Context) { throw new ArgumentException(Impl.ActivityMonitorResources.ActivityMonitorTagMustBeRegistered, "tag"); } Tag = tag; Text = conclusion; }
CKTrait FindOrCreateAtomicTrait(string trait, bool create) { CKTrait m; if (!_traits.TryGetValue(trait, out m) && create) { lock ( _creationLock ) { if (!_traits.TryGetValue(trait, out m)) { m = new CKTrait(this, trait); _traits[trait] = m; } } Debug.Assert(m.IsAtomic, "Special construction for atomic traits."); } return(m); }
/// <summary> /// Writes all information. /// </summary> /// <param name="data">Log data.</param> protected override void OnContinueOnSameLevel(ActivityMonitorLogData data) { var w = _buffer.Clear(); w.AppendMultiLine(_prefixLevel, data.Text, true); if (_currentTags != data.Tags) { w.Append(" -[").Append(data.Tags).Append(']'); _currentTags = data.Tags; } w.AppendLine(); if (data.Exception != null) { DumpException(w, _prefix, !data.IsTextTheExceptionMessage, data.Exception); } _writer(_buffer.ToString()); }
/// <summary> /// Initializes a new context for traits with the given separator. /// </summary> /// <param name="name">Name for the context. Must not be null nor whitespace.</param> /// <param name="separator">Separator if it must differ from '|'.</param> public CKTraitContext(string name, char separator = '|') { if (String.IsNullOrWhiteSpace(name)) { throw new ArgumentException(Impl.CoreResources.ArgumentMustNotBeNullOrWhiteSpace, "uniqueName"); } _uniqueName = name.Normalize(); _uniqueIndex = Interlocked.Increment(ref _index); _separator = separator; _separatorString = new String(separator, 1); string pattern = "(\\s*" + Regex.Escape(_separatorString) + "\\s*)+"; _canonize2 = new Regex(pattern, RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.CultureInvariant); _empty = new CKTrait(this); _traits = new ConcurrentDictionary <string, CKTrait>(StringComparer.Ordinal); _traits[String.Empty] = _empty; _enumerableWithEmpty = new CKTrait[] { _empty }; _creationLock = new Object(); }
/// <summary> /// Obtains a trait from a list of atomic (already sorted) traits. /// Used by fall back generation. /// </summary> internal CKTrait FindOrCreate(CKTrait[] atomicTraits, int count) { Debug.Assert(count > 1, "Atomic traits are handled directly."); Debug.Assert(!Array.Exists(atomicTraits, mA => mA.Context != this || mA.AtomicTraits.Count != 1), "Traits are from this Context and they are atomic and not empty."); StringBuilder b = new StringBuilder(atomicTraits[0].ToString()); for (int i = 1; i < count; ++i) { Debug.Assert(StringComparer.Ordinal.Compare(atomicTraits[i - 1].ToString(), atomicTraits[i].ToString()) < 0, "Traits are already sorted and NO DUPLICATE exists."); b.Append(_separator).Append(atomicTraits[i].ToString()); } string traits = b.ToString(); CKTrait m; if (!_traits.TryGetValue(traits, out m)) { // We must clone the array since fall backs generation reuses it. if (atomicTraits.Length != count) { CKTrait[] subArray = new CKTrait[count]; Array.Copy(atomicTraits, subArray, count); atomicTraits = subArray; } else { atomicTraits = (CKTrait[])atomicTraits.Clone(); } lock ( _creationLock ) { if (!_traits.TryGetValue(traits, out m)) { m = new CKTrait(this, traits, atomicTraits); _traits[traits] = m; } } } return(m); }
void Build(ActivityMonitorOutput output, CKTrait tags, bool applyAutoConfigurations) { Debug.Assert(Tags.Context.Separator == '|', "Separator must be the |."); _output = output; _groups = new Group[8]; for (int i = 0; i < _groups.Length; ++i) { _groups[i] = new Group(this, i); } _currentTag = tags ?? Tags.Empty; _uniqueId = Guid.NewGuid(); _topic = String.Empty; _lastLogTime = DateTimeStamp.MinValue; if (applyAutoConfigurations) { var autoConf = AutoConfiguration; if (autoConf != null) { autoConf(this); } } }
/// <summary> /// Obtains a trait from a list of atomic (already sorted) traits. /// Used by the Add, Toggle, Remove, Intersect methods. /// </summary> internal CKTrait FindOrCreate(List <CKTrait> atomicTraits) { if (atomicTraits.Count == 0) { return(_empty); } Debug.Assert(atomicTraits[0].Context == this, "This is one of our traits."); Debug.Assert(atomicTraits[0].AtomicTraits.Count == 1, "This is an atomic trait and not the empty one."); if (atomicTraits.Count == 1) { return(atomicTraits[0]); } StringBuilder b = new StringBuilder(atomicTraits[0].ToString()); for (int i = 1; i < atomicTraits.Count; ++i) { Debug.Assert(atomicTraits[i].Context == this, "This is one of our traits."); Debug.Assert(atomicTraits[i].AtomicTraits.Count == 1, "This is an atomic trait and not the empty one."); Debug.Assert(StringComparer.Ordinal.Compare(atomicTraits[i - 1].ToString(), atomicTraits[i].ToString()) < 0, "Traits are already sorted and NO DUPLICATES exist."); b.Append(_separator).Append(atomicTraits[i].ToString()); } string traits = b.ToString(); CKTrait m; if (!_traits.TryGetValue(traits, out m)) { lock ( _creationLock ) { if (!_traits.TryGetValue(traits, out m)) { m = new CKTrait(this, traits, atomicTraits.ToArray()); _traits[traits] = m; } } } return(m); }
/// <summary> /// Writes a group opening. /// </summary> /// <param name="g">Group information.</param> protected override void OnGroupOpen(IActivityLogGroup g) { var w = _buffer.Clear(); string levelLabel = g.MaskedGroupLevel.ToString(); string start = string.Format("{0}> {1}: ", _prefix, levelLabel); _prefix += "| "; _prefixLevel = _prefix; string prefixLabel = _prefixLevel + new string( ' ', levelLabel.Length + 1 ); w.Append(start).AppendMultiLine(prefixLabel, g.GroupText, false); if (_currentTags != g.GroupTags) { w.Append(" -[").Append(g.GroupTags).Append(']'); _currentTags = g.GroupTags; } w.AppendLine(); if (g.Exception != null) { DumpException(w, _prefix, !g.IsGroupTextTheExceptionMessage, g.Exception); } _writer(_buffer.ToString()); }