Activity
using System.Collections.Generic;
using System.Threading;
namespace System.Diagnostics
{
public class Activity
{
private class KeyValueListNode
{
public KeyValuePair<string, string> keyValue;
public KeyValueListNode Next;
}
private string _rootId;
private int _currentChildId;
private static readonly string s_uniqSuffix = "-" + GetRandomNumber().ToString("x") + ".";
private static long s_currentRootId = (uint)GetRandomNumber();
private const int RequestIdMaxLength = 1024;
private KeyValueListNode ;
private KeyValueListNode _baggage;
private bool isFinished;
private static readonly AsyncLocal<Activity> s_current = new AsyncLocal<Activity>();
public string OperationName { get; }
public string Id { get; set; }
public DateTime StartTimeUtc { get; set; }
public Activity Parent { get; set; }
public string ParentId { get; set; }
public string RootId {
get {
if (_rootId == null) {
if (Id != null)
_rootId = GetRootId(Id);
else if (ParentId != null) {
_rootId = GetRootId(ParentId);
}
}
return _rootId;
}
}
public IEnumerable<KeyValuePair<string, string>> Tags {
get {
for (KeyValueListNode tags = _tags; tags != null; tags = tags.Next) {
yield return tags.keyValue;
}
}
}
public IEnumerable<KeyValuePair<string, string>> Baggage {
get {
for (Activity activity = this; activity != null; activity = activity.Parent) {
for (KeyValueListNode baggage = activity._baggage; baggage != null; baggage = baggage.Next) {
yield return baggage.keyValue;
}
}
}
}
public TimeSpan Duration { get; set; }
public static Activity Current {
get {
return s_current.Value;
}
set {
if (ValidateSetCurrent(value))
SetCurrent(value);
}
}
public string GetBaggageItem(string key)
{
foreach (KeyValuePair<string, string> item in Baggage) {
if (key == item.Key)
return item.Value;
}
return null;
}
public Activity(string operationName)
{
if (string.IsNullOrEmpty(operationName))
NotifyError(new ArgumentException("operationName must not be null or empty"));
else
OperationName = operationName;
}
public Activity AddTag(string key, string value)
{
_tags = new KeyValueListNode {
keyValue = new KeyValuePair<string, string>(key, value),
Next = _tags
};
return this;
}
public Activity AddBaggage(string key, string value)
{
_baggage = new KeyValueListNode {
keyValue = new KeyValuePair<string, string>(key, value),
Next = _baggage
};
return this;
}
public Activity SetParentId(string parentId)
{
if (Parent != null)
NotifyError(new InvalidOperationException("Trying to set ParentId on activity which has Parent"));
else if (ParentId != null) {
NotifyError(new InvalidOperationException("ParentId is already set"));
} else if (string.IsNullOrEmpty(parentId)) {
NotifyError(new ArgumentException("parentId must not be null or empty"));
} else {
ParentId = parentId;
}
return this;
}
public Activity SetStartTime(DateTime startTimeUtc)
{
if (startTimeUtc.Kind != DateTimeKind.Utc)
NotifyError(new InvalidOperationException("startTimeUtc is not UTC"));
else
StartTimeUtc = startTimeUtc;
return this;
}
public Activity SetEndTime(DateTime endTimeUtc)
{
if (endTimeUtc.Kind != DateTimeKind.Utc)
NotifyError(new InvalidOperationException("endTimeUtc is not UTC"));
else {
Duration = endTimeUtc - StartTimeUtc;
if (Duration.Ticks <= 0)
Duration = new TimeSpan(1);
}
return this;
}
public Activity Start()
{
if (Id != null)
NotifyError(new InvalidOperationException("Trying to start an Activity that was already started"));
else {
if (ParentId == null) {
Activity current = Current;
if (current != null) {
ParentId = current.Id;
Parent = current;
}
}
if (StartTimeUtc == default(DateTime))
StartTimeUtc = GetUtcNow();
Id = GenerateId();
SetCurrent(this);
}
return this;
}
public void Stop()
{
if (Id == null)
NotifyError(new InvalidOperationException("Trying to stop an Activity that was not started"));
else if (!isFinished) {
isFinished = true;
if (Duration == TimeSpan.Zero)
SetEndTime(GetUtcNow());
SetCurrent(Parent);
}
}
private static void NotifyError(Exception exception)
{
try {
throw exception;
} catch {
}
}
private string GenerateId()
{
if (Parent == null) {
if (ParentId == null)
return GenerateRootId();
string text = (ParentId[0] == '|') ? ParentId : ("|" + ParentId);
char c = text[text.Length - 1];
if (c != '.' && c != '_')
text += ".";
return AppendSuffix(text, Interlocked.Increment(ref s_currentRootId).ToString("x"), '_');
}
return AppendSuffix(Parent.Id, Interlocked.Increment(ref Parent._currentChildId).ToString(), '.');
}
private string GetRootId(string id)
{
int num = id.IndexOf('.');
if (num < 0)
num = id.Length;
int num2 = (id[0] == '|') ? 1 : 0;
return id.Substring(num2, num - num2);
}
private string AppendSuffix(string parentId, string suffix, char delimiter)
{
if (parentId.Length + suffix.Length < 1024)
return parentId + suffix + delimiter.ToString();
int num = 1015;
while (num > 1 && parentId[num - 1] != '.' && parentId[num - 1] != '_') {
num--;
}
if (num == 1)
return GenerateRootId();
string str = ((int)GetRandomNumber()).ToString("x8");
return parentId.Substring(0, num) + str + "#";
}
private string GenerateRootId()
{
return "|" + Interlocked.Increment(ref s_currentRootId).ToString("x") + s_uniqSuffix;
}
private unsafe static long GetRandomNumber()
{
Guid guid = Guid.NewGuid();
return *(long*)(&guid);
}
private static bool ValidateSetCurrent(Activity activity)
{
bool flag = activity == null || (activity.Id != null && !activity.isFinished);
if (!flag)
NotifyError(new InvalidOperationException("Trying to set an Activity that is not running"));
return flag;
}
private static void SetCurrent(Activity activity)
{
s_current.Value = activity;
}
internal static DateTime GetUtcNow()
{
return DateTime.UtcNow;
}
}
}