Exemplo n.º 1
0
        public override void EventProcessing(EventContext context)
        {
            if (!context.Event.IsError())
                return;

            Error error = context.Event.GetError();
            if (error == null)
                return;

            if (String.IsNullOrWhiteSpace(context.Event.Message))
                context.Event.Message = error.Message;

            string[] commonUserMethods = { "DataContext.SubmitChanges", "Entities.SaveChanges" };
            if (context.HasProperty("CommonMethods"))
                commonUserMethods = context.GetProperty<string>("CommonMethods").SplitAndTrim(',');

            string[] userNamespaces = null;
            if (context.HasProperty("UserNamespaces"))
                userNamespaces = context.GetProperty<string>("UserNamespaces").SplitAndTrim(',');

            var signature = new ErrorSignature(error, userCommonMethods: commonUserMethods, userNamespaces: userNamespaces);
            if (signature.SignatureInfo.Count <= 0)
                return;

            foreach (var key in signature.SignatureInfo.Keys)
                context.StackSignatureData.Add(key, signature.SignatureInfo[key]);
        }
Exemplo n.º 2
0
        private async Task SetBrowserOsAndDeviceFromUserAgent(RequestInfo request, EventContext context) {
            var info = await _parser.ParseAsync(request.UserAgent, context.Project.Id).AnyContext();
            if (info != null) {
                if (!String.Equals(info.UserAgent.Family, "Other")) {
                    request.Data[RequestInfo.KnownDataKeys.Browser] = info.UserAgent.Family;
                    if (!String.IsNullOrEmpty(info.UserAgent.Major)) {
                        request.Data[RequestInfo.KnownDataKeys.BrowserVersion] = String.Join(".", new[] { info.UserAgent.Major, info.UserAgent.Minor, info.UserAgent.Patch }.Where(v => !String.IsNullOrEmpty(v)));
                        request.Data[RequestInfo.KnownDataKeys.BrowserMajorVersion] = info.UserAgent.Major;
                    }
                }

                if (!String.Equals(info.Device.Family, "Other"))
                    request.Data[RequestInfo.KnownDataKeys.Device] = info.Device.Family;

                if (!String.Equals(info.OS.Family, "Other")) {
                    request.Data[RequestInfo.KnownDataKeys.OS] = info.OS.Family;
                    if (!String.IsNullOrEmpty(info.OS.Major)) {
                        request.Data[RequestInfo.KnownDataKeys.OSVersion] = String.Join(".", new[] { info.OS.Major, info.OS.Minor, info.OS.Patch }.Where(v => !String.IsNullOrEmpty(v)));
                        request.Data[RequestInfo.KnownDataKeys.OSMajorVersion] = info.OS.Major;
                    }
                }

                var botPatterns = context.Project.Configuration.Settings.GetStringCollection(SettingsDictionary.KnownKeys.UserAgentBotPatterns).ToList();
                request.Data[RequestInfo.KnownDataKeys.IsBot] = info.Device.IsSpider || request.UserAgent.AnyWildcardMatches(botPatterns);
            }
        }
        public override void Process(EventContext ctx) {
            if (ctx.StackInfo == null || !ctx.StackInfo.OccurrencesAreCritical)
                return;

            Log.Trace().Message("Marking error as critical.").Write();
            ctx.Event.MarkAsCritical();
        }
        public override void EventProcessing(EventContext context)
        {
            if (Settings.Current.WebsiteMode == WebsiteMode.Dev)
                return;

            var project = _projectRepository.GetById(context.Event.ProjectId);
            if (project == null || !project.DeleteBotDataEnabled)
                return;

            // Throttle errors by client ip address to no more than X every 5 minutes.
            var ri = context.Event.GetRequestInfo();
            if (ri == null || String.IsNullOrEmpty(ri.ClientIpAddress))
                return;

            string throttleCacheKey = String.Concat("bot:", ri.ClientIpAddress, ":", DateTime.Now.Floor(_throttlingPeriod).Ticks);
            var requestCount = _cacheClient.Get<int?>(throttleCacheKey);
            if (requestCount != null) {
                _cacheClient.Increment(throttleCacheKey, 1);
                requestCount++;
            } else {
                _cacheClient.Set(throttleCacheKey, 1, _throttlingPeriod);
                requestCount = 1;
            }

            if (requestCount < Settings.Current.BotThrottleLimit)
                return;

            Log.Info().Message("Bot throttle triggered. IP: {0} Time: {1} Project: {2}", ri.ClientIpAddress, DateTime.Now.Floor(_throttlingPeriod), context.Event.ProjectId).Project(context.Event.ProjectId).Write();
            // the throttle was triggered, go and delete all the errors that triggered the throttle to reduce bot noise in the system
            Task.Run(() => _eventRepository.HideAllByClientIpAndDateAsync(context.Event.OrganizationId, ri.ClientIpAddress, DateTime.Now.Floor(_throttlingPeriod), DateTime.Now.Ceiling(_throttlingPeriod)));
            context.IsCancelled = true;
        }
        public override void Process(EventContext ctx)
        {
            // if they don't have premium features, then we don't need to queue notifications
            if (!ctx.Organization.HasPremiumFeatures)
                return;

            _notificationQueue.EnqueueAsync(new EventNotification {
                Event = ctx.Event,
                IsNew = ctx.IsNew,
                IsCritical = ctx.Event.IsCritical(),
                IsRegression = ctx.IsRegression,
                //TotalOccurrences = ctx.Stack.TotalOccurrences,
                ProjectName = ctx.Project.Name
            }).Wait();

            foreach (WebHook hook in _webHookRepository.GetByOrganizationIdOrProjectId(ctx.Event.OrganizationId, ctx.Event.ProjectId)) {
                bool shouldCall = hook.EventTypes.Contains(WebHookRepository.EventTypes.NewError) && ctx.IsNew
                                  || hook.EventTypes.Contains(WebHookRepository.EventTypes.ErrorRegression) && ctx.IsRegression
                                  || hook.EventTypes.Contains(WebHookRepository.EventTypes.CriticalError) && ctx.Event.Tags != null && ctx.Event.Tags.Contains("Critical");

                if (!shouldCall)
                    continue;

                Log.Trace().Project(ctx.Event.ProjectId).Message("Web hook queued: project={0} url={1}", ctx.Event.ProjectId, hook.Url).Write();

                // TODO: Should we be using the hook's project id and organization id?
                var context = new WebHookDataContext(hook.Version, ctx.Event, ctx.Organization, ctx.Project, ctx.Stack, ctx.IsNew, ctx.IsRegression);
                _webHookNotificationQueue.EnqueueAsync(new WebHookNotification {
                    OrganizationId = ctx.Event.OrganizationId,
                    ProjectId = ctx.Event.ProjectId,
                    Url = hook.Url,
                    Data = _webHookDataPluginManager.CreateFromEvent(context)
                }).Wait();
            }
        }
        public override Task EventProcessingAsync(EventContext context) {
            var data = context.Event.Data;
            if (data.ContainsKey(Event.KnownDataKeys.ManualStackingKey) && data[Event.KnownDataKeys.ManualStackingKey] != null)
                context.StackSignatureData.AddItemIfNotEmpty(nameof(Event.KnownDataKeys.ManualStackingKey), data[Event.KnownDataKeys.ManualStackingKey].ToString());

            return Task.CompletedTask;
        }
        public override async Task ProcessAsync(EventContext ctx) {
            // if they don't have premium features, then we don't need to queue notifications
            if (!ctx.Organization.HasPremiumFeatures)
                return;

            if (ShouldQueueNotification(ctx))
                await _notificationQueue.EnqueueAsync(new EventNotificationWorkItem {
                    EventId = ctx.Event.Id,
                    IsNew = ctx.IsNew,
                    IsCritical = ctx.Event.IsCritical(),
                    IsRegression = ctx.IsRegression,
                    TotalOccurrences = ctx.Stack.TotalOccurrences,
                    ProjectName = ctx.Project.Name
                }).AnyContext();

            foreach (WebHook hook in (await _webHookRepository.GetByOrganizationIdOrProjectIdAsync(ctx.Event.OrganizationId, ctx.Event.ProjectId).AnyContext()).Documents) {
                if (!ShouldCallWebHook(hook, ctx))
                    continue;

                var context = new WebHookDataContext(hook.Version, ctx.Event, ctx.Organization, ctx.Project, ctx.Stack, ctx.IsNew, ctx.IsRegression);
                var notification = new WebHookNotification {
                    OrganizationId = ctx.Event.OrganizationId,
                    ProjectId = ctx.Event.ProjectId,
                    Url = hook.Url,
                    Data = await _webHookDataPluginManager.CreateFromEventAsync(context).AnyContext()
                };

                await _webHookNotificationQueue.EnqueueAsync(notification).AnyContext();
                Logger.Trace().Project(ctx.Event.ProjectId).Message("Web hook queued: project={0} url={1}", ctx.Event.ProjectId, hook.Url).Property("Web Hook Notification", notification).Write();
            }
        }
Exemplo n.º 8
0
        public override Task EventProcessingAsync(EventContext context) {
            if (!context.Event.IsError())
                return Task.CompletedTask;

            Error error = context.Event.GetError();
            if (error == null)
                return Task.CompletedTask;

            if (String.IsNullOrWhiteSpace(context.Event.Message))
                context.Event.Message = error.Message;

            string[] commonUserMethods = { "DataContext.SubmitChanges", "Entities.SaveChanges" };
            if (context.HasProperty("CommonMethods"))
                commonUserMethods = context.GetProperty<string>("CommonMethods").SplitAndTrim(',');

            string[] userNamespaces = null;
            if (context.HasProperty("UserNamespaces"))
                userNamespaces = context.GetProperty<string>("UserNamespaces").SplitAndTrim(',');

            var signature = new ErrorSignature(error, userCommonMethods: commonUserMethods, userNamespaces: userNamespaces);
            if (signature.SignatureInfo.Count <= 0)
                return Task.CompletedTask;

            var targetInfo = new SettingsDictionary(signature.SignatureInfo);
            var stackingTarget = error.GetStackingTarget();
            if (stackingTarget?.Error?.StackTrace != null && stackingTarget.Error.StackTrace.Count > 0 && !targetInfo.ContainsKey("Message"))
                targetInfo["Message"] = stackingTarget.Error.Message;

            error.Data[Error.KnownDataKeys.TargetInfo] = targetInfo;

            foreach (var key in signature.SignatureInfo.Keys)
                context.StackSignatureData.Add(key, signature.SignatureInfo[key]);

            return Task.CompletedTask;
        }
        public override async Task ProcessAsync(EventContext ctx) {
            if (ctx.Stack == null || !ctx.Stack.OccurrencesAreCritical)
                return;

            Log.Trace().Message("Marking error as critical.").Write();
            ctx.Event.MarkAsCritical();
        }
        public async Task AddManualStackSignatureData(string dataKey, string dataValue, bool willAddManualStackSignature) {
            var plugin = new ManualStackingPlugin();
            var data = new DataDictionary() { { dataKey, dataValue } };
            var context = new EventContext(new PersistentEvent { Data = data });

            await plugin.EventBatchProcessingAsync(new List<EventContext> { context });
            Assert.Equal(willAddManualStackSignature, context.StackSignatureData.Count > 0);
        }
        public override Task ProcessAsync(EventContext ctx) {
            if (ctx.Stack == null || !ctx.Stack.OccurrencesAreCritical)
                return Task.CompletedTask;

            _logger.Trace("Marking error as critical.");
            ctx.Event.MarkAsCritical();

            return Task.CompletedTask;
        }
Exemplo n.º 12
0
 public override void Process(EventContext ctx)
 {
     try {
         ctx.Event = _eventRepository.Add(ctx.Event);
     } catch (DuplicateDocumentException ex) {
         Log.Info().Project(ctx.Event.ProjectId).Message("Ignoring duplicate error submission: {0}", ctx.Event.Id).Write();
         ctx.IsCancelled = true;
     }
 }
Exemplo n.º 13
0
        public async Task AddManualStackSignatureData(string stackingKey, bool willAddManualStackSignature) {
            var ev = new PersistentEvent();
            ev.SetManualStackingKey(stackingKey);

            var context = new EventContext(ev);
            var plugin = new ManualStackingPlugin();
            await plugin.EventBatchProcessingAsync(new List<EventContext> { context });
            Assert.Equal(willAddManualStackSignature, context.StackSignatureData.Count > 0);
        }
        public override Task EventProcessingAsync(EventContext context) {
            var msi = context.Event.GetManualStackingInfo();
            if (msi?.SignatureData != null) {
                foreach (var kvp in msi.SignatureData)
                    context.StackSignatureData.AddItemIfNotEmpty(kvp.Key, kvp.Value);
            }

            return Task.CompletedTask;
        }
        public override Task ProcessAsync(EventContext ctx) {
            if (!ctx.Organization.HasPremiumFeatures)
                return Task.CompletedTask;

            // TODO: Do we need a pipeline action to trim keys and remove null values that may be sent by other native clients.
            ctx.Event.CopyDataToIndex();

            return Task.CompletedTask;
        }
        public override async Task EventProcessingAsync(EventContext context) {
            if (String.IsNullOrEmpty(context.Event.ReferenceId))
                return;

            // TODO: Look into using a lock on reference id so we can ensure there is no race conditions with setting keys
            if (await _cacheClient.AddAsync(GetCacheKey(context), true, TimeSpan.FromMinutes(1)).AnyContext())
                return;

            context.IsCancelled = true;
        }
        public override void Process(EventContext ctx)
        {
            if (ctx.Organization.RetentionDays <= 0)
                return;

            if (DateTimeOffset.Now.UtcDateTime.Subtract(ctx.Event.Date.UtcDateTime).Days <= ctx.Organization.RetentionDays)
                return;

            Log.Info().Project(ctx.Event.ProjectId).Message("Discarding event that occurred outside of your retention limit.").Write();
            ctx.IsCancelled = true;
        }
        public override void Process(EventContext ctx)
        {
            if (ctx.Event.Tags != null)
                ctx.Event.Tags.RemoveWhere(t => String.IsNullOrEmpty(t) || t.Length > 255);

            if (ctx.Event.Message != null && ctx.Event.Message.Length > 2000)
                ctx.Event.Message = ctx.Event.Message.Truncate(2000);

            if (ctx.Event.Source != null && ctx.Event.Source.Length > 2000)
                ctx.Event.Source = ctx.Event.Source.Truncate(2000);
        }
        public override async Task EventProcessingAsync(EventContext context) {
            if (String.IsNullOrEmpty(context.Event.ReferenceId))
                return;

            // TODO: Look into using a lock on reference id so we can ensure there is no race conditions with setting keys
            if (await _cacheClient.AddAsync(GetCacheKey(context), true, TimeSpan.FromMinutes(1)).AnyContext())
                return;

            _logger.Warn().Project(context.Event.ProjectId).Message("Discarding event due to duplicate reference id: {0}", context.Event.ReferenceId).Write();
            context.IsCancelled = true;
        }
        public override void Process(EventContext ctx)
        {
            // TODO: Implement batch incrementing to reduce pipeline cost.
            //_organizationCounters.AddOrUpdate(ctx.Event.OrganizationId, 1, (key, value) => value + 1);
            //_projectCounters.AddOrUpdate(ctx.Event.ProjectId, 1, (key, value) => value + 1);

            _organizationRepository.IncrementEventCounter(ctx.Event.OrganizationId);
            _projectRepository.IncrementEventCounter(ctx.Event.ProjectId);
            if (!ctx.IsNew)
                _stackRepository.IncrementEventCounter(ctx.Event.OrganizationId, ctx.Event.StackId, ctx.Event.Date.UtcDateTime);
        }
Exemplo n.º 21
0
        public override void EventProcessing(EventContext context)
        {
            var request = context.Event.GetRequestInfo();
            if (request == null)
                return;

            var exclusions = context.Project.Configuration.Settings.ContainsKey(SettingsDictionary.KnownKeys.DataExclusions)
                    ? DefaultExclusions.Union(context.Project.Configuration.Settings.GetStringCollection(SettingsDictionary.KnownKeys.DataExclusions)).ToList()
                    : DefaultExclusions;

            context.Event.AddRequestInfo(request.ApplyDataExclusions(exclusions, MAX_VALUE_LENGTH));
        }
 public override void Process(EventContext ctx) {
     Task.Factory.StartNewDelayed(1500, () => _publisher.Publish(new EventOccurrence {
         Id = ctx.Event.Id,
         OrganizationId = ctx.Event.OrganizationId,
         ProjectId = ctx.Event.ProjectId,
         StackId = ctx.Event.StackId,
         Type = ctx.Event.Type,
         IsHidden = ctx.Event.IsHidden,
         IsFixed = ctx.Event.IsFixed,
         IsNotFound = ctx.Event.IsNotFound(),
         IsRegression = ctx.IsRegression
     }));
 }
        public override void Process(EventContext ctx) {
            if (ctx.StackInfo == null || !ctx.StackInfo.DateFixed.HasValue || ctx.StackInfo.DateFixed.Value >= ctx.Event.Date.UtcDateTime)
                return;

            Log.Trace().Message("Marking event as an regression.").Write();
            _stackRepository.MarkAsRegressed(ctx.StackInfo.Id);
            _eventRepository.MarkAsRegressedByStack(ctx.StackInfo.Id);

            string signatureHash = ctx.GetProperty<string>("__SignatureHash");
            _stackRepository.InvalidateCache(ctx.Event.StackId, signatureHash, ctx.Event.ProjectId);

            ctx.Event.IsFixed = false;
            ctx.IsRegression = true;
        }
        public override async Task ProcessAsync(EventContext ctx) {
            if (ctx.Event.Tags != null)
                ctx.Event.Tags.RemoveWhere(t => String.IsNullOrEmpty(t) || t.Length > 255);

            if (ctx.Event.Message != null && ctx.Event.Message.Length > 2000)
                ctx.Event.Message = ctx.Event.Message.Truncate(2000);
            else if (String.IsNullOrEmpty(ctx.Event.Message))
                ctx.Event.Message = null;

            if (ctx.Event.Source != null && ctx.Event.Source.Length > 2000)
                ctx.Event.Source = ctx.Event.Source.Truncate(2000);
            else if (String.IsNullOrEmpty(ctx.Event.Source))
                ctx.Event.Source = null;
        }
 public override void Process(EventContext ctx)
 {
     _publisher.PublishAsync(new EventOccurrence {
         Id = ctx.Event.Id,
         OrganizationId = ctx.Event.OrganizationId,
         ProjectId = ctx.Event.ProjectId,
         StackId = ctx.Event.StackId,
         Type = ctx.Event.Type,
         IsHidden = ctx.Event.IsHidden,
         IsFixed = ctx.Event.IsFixed,
         IsNotFound = ctx.Event.IsNotFound(),
         IsRegression = ctx.IsRegression
     });
 }
        public override async Task ProcessAsync(EventContext ctx) {
            if (ctx.Organization.RetentionDays <= 0)
                return;

            // If the date is in the future, set it to now using the same offset.
            if (DateTimeOffset.Now.UtcDateTime < ctx.Event.Date.UtcDateTime)
                ctx.Event.Date = ctx.Event.Date.Subtract(ctx.Event.Date.UtcDateTime - DateTimeOffset.UtcNow);

            // Discard events that are being submitted outside of the plan retention limit.
            if (DateTimeOffset.Now.UtcDateTime.Subtract(ctx.Event.Date.UtcDateTime).Days <= ctx.Organization.RetentionDays)
                return;

            Log.Info().Project(ctx.Event.ProjectId).Message("Discarding event that occurred outside of your retention limit.").Write();
            ctx.IsCancelled = true;
        }
        public override void EventProcessing(EventContext context) {
            if (!context.Event.IsError())
                return;

            SimpleError error = context.Event.GetSimpleError();
            if (error == null)
                return;
            
            if (String.IsNullOrWhiteSpace(context.Event.Message))
                context.Event.Message = error.Message;

            // TODO: Parse the stack trace and run it through the ErrorSignature.
            context.StackSignatureData.Add("ExceptionType", error.Type);
            context.StackSignatureData.Add("StackTrace", error.StackTrace.ToSHA1());
        }
        public override Task ProcessAsync(EventContext ctx) {
            ctx.Event.Tags?.RemoveWhere(t => String.IsNullOrEmpty(t) || t.Length > 255);

            if (ctx.Event.Message != null && ctx.Event.Message.Length > 2000)
                ctx.Event.Message = ctx.Event.Message.Truncate(2000);
            else if (String.IsNullOrEmpty(ctx.Event.Message))
                ctx.Event.Message = null;

            if (ctx.Event.Source != null && ctx.Event.Source.Length > 2000)
                ctx.Event.Source = ctx.Event.Source.Truncate(2000);
            else if (String.IsNullOrEmpty(ctx.Event.Source))
                ctx.Event.Source = null;

            return TaskHelper.Completed();
        }
Exemplo n.º 29
0
        public override Task EventProcessingAsync(EventContext context) {
            var request = context.Event.GetRequestInfo();
            if (request == null)
                return TaskHelper.Completed();

            var exclusions = context.Project.Configuration.Settings.ContainsKey(SettingsDictionary.KnownKeys.DataExclusions)
                    ? DefaultExclusions.Union(context.Project.Configuration.Settings.GetStringCollection(SettingsDictionary.KnownKeys.DataExclusions)).ToList()
                    : DefaultExclusions;

            if (!String.IsNullOrEmpty(request.UserAgent)) {
                try {
                    var info = Parser.GetDefault().Parse(request.UserAgent);

                    if (!String.Equals(info.UserAgent.Family, "Other")) {
                        request.Data[RequestInfo.KnownDataKeys.Browser] = info.UserAgent.Family;
                        if (!String.IsNullOrEmpty(info.UserAgent.Major)) {
                            request.Data[RequestInfo.KnownDataKeys.BrowserVersion] = String.Join(".", new[] { info.UserAgent.Major, info.UserAgent.Minor, info.UserAgent.Patch }.Where(v => !String.IsNullOrEmpty(v)));
                            request.Data[RequestInfo.KnownDataKeys.BrowserMajorVersion] = info.UserAgent.Major;
                        }
                    }

                    if (!String.Equals(info.Device.Family, "Other"))
                        request.Data[RequestInfo.KnownDataKeys.Device] = info.Device.Family;


                    if (!String.Equals(info.OS.Family, "Other")) {
                        request.Data[RequestInfo.KnownDataKeys.OS] = info.OS.Family;
                        if (!String.IsNullOrEmpty(info.OS.Major)) {
                            request.Data[RequestInfo.KnownDataKeys.OSVersion] = String.Join(".", new[] { info.OS.Major, info.OS.Minor, info.OS.Patch }.Where(v => !String.IsNullOrEmpty(v)));
                            request.Data[RequestInfo.KnownDataKeys.OSMajorVersion] = info.OS.Major;
                        }
                    }

                    var botPatterns = context.Project.Configuration.Settings.ContainsKey(SettingsDictionary.KnownKeys.UserAgentBotPatterns)
                      ? context.Project.Configuration.Settings.GetStringCollection(SettingsDictionary.KnownKeys.UserAgentBotPatterns).ToList()
                      : new List<string>();

                    request.Data[RequestInfo.KnownDataKeys.IsBot] = info.Device.IsSpider || request.UserAgent.AnyWildcardMatches(botPatterns);
                } catch (Exception ex) {
                    Log.Warn().Project(context.Event.ProjectId).Message("Unable to parse user agent {0}. Exception: {1}", request.UserAgent, ex.Message).Write();
                }
            }

            context.Event.AddRequestInfo(request.ApplyDataExclusions(exclusions, MAX_VALUE_LENGTH));

            return TaskHelper.Completed();
        }
        public override Task ProcessAsync(EventContext ctx) {
            if (!ctx.Organization.HasPremiumFeatures)
                return TaskHelper.Completed();

            // TODO: Do we need a pipeline action to trim keys and remove null values that may be sent by other native clients.
            foreach (string key in ctx.Event.Data.Keys.Where(k => !k.StartsWith("@")).ToArray()) {
                string field = key.Trim().ToLower().Replace(' ', '-');
                if (field.StartsWith("@") || ctx.Event.Data[key] == null)
                    continue;

                Type dataType = ctx.Event.Data[key].GetType();
                if (dataType == typeof(bool)) {
                    ctx.Event.Idx[field + "-b"] = ctx.Event.Data[key];
                } else if (dataType.IsNumeric()) {
                    ctx.Event.Idx[field + "-n"] = ctx.Event.Data[key];
                } else if (dataType == typeof(DateTime) || dataType == typeof(DateTimeOffset)) {
                    ctx.Event.Idx[field + "-d"] = ctx.Event.Data[key];
                } else if (dataType == typeof(string)) {
                    var input = (string)ctx.Event.Data[key];
                    if (String.IsNullOrEmpty(input) || input.Length >= 1000)
                        continue;

                    if (input.GetJsonType() != JsonType.None)
                        continue;

                    if (input[0] == '"')
                        input = input.TrimStart('"').TrimEnd('"');

                    bool value;
                    DateTimeOffset dtoValue;
                    Decimal decValue;
                    Double dblValue;
                    if (Boolean.TryParse(input, out value))
                        ctx.Event.Idx[field + "-b"] = value;
                    else if (DateTimeOffset.TryParse(input, out dtoValue))
                        ctx.Event.Idx[field + "-d"] = dtoValue;
                    else if (Decimal.TryParse(input, out decValue))
                        ctx.Event.Idx[field + "-n"] = decValue;
                    else if (Double.TryParse(input, out dblValue))
                        ctx.Event.Idx[field + "-n"] = dblValue;
                    else
                        ctx.Event.Idx[field + "-s"] = input;
                }
            }

            return TaskHelper.Completed();
        }
 private string GetCacheKey(EventContext context)
 {
     return(String.Concat("Project:", context.Project.Id, ":", context.Event.ReferenceId));
 }