コード例 #1
0
        public void CanGetEventTermStatsByTag()
        {
            // capture start date before generating data to make sure that our time range for stats includes all items
            var       startDate  = DateTime.UtcNow.SubtractDays(60);
            const int eventCount = 100;

            RemoveData();
            CreateData(eventCount, false);

            _client.Refresh(d => d.Force());
            _statsClient.DisplayStats();
            var result = _stats.GetTermsStats(startDate, DateTime.UtcNow, "tags", null, userFilter: "project:" + TestConstants.ProjectId);

            Assert.Equal(eventCount, result.Total);
            // each event can be in multiple tag buckets since an event can have up to 3 sample tags
            Assert.InRange(result.Terms.Sum(t => t.Total), eventCount, eventCount * 3);
            Assert.InRange(result.Terms.Sum(t => t.New), 1, 25 * TestConstants.EventTags.Count);
            Assert.InRange(result.Terms.Count, 1, TestConstants.EventTags.Count);
            foreach (var term in result.Terms)
            {
                Assert.InRange(term.New, 1, 25);
                //Assert.InRange(term.Unique, 1, 25);
                Assert.Equal(term.Total, term.Timeline.Sum(t => t.Total));
            }
        }
コード例 #2
0
        private IHttpActionResult FrequentInternal(string systemFilter = null, string userFilter = null, string time = null, string offset = null, string mode = null, int page = 1, int limit = 10)
        {
            page  = GetPage(page);
            limit = GetLimit(limit);
            var skip = GetSkip(page, limit);

            if (skip > MAXIMUM_SKIP)
            {
                return(Ok(new object[0]));
            }

            var validationResult = QueryProcessor.Process(userFilter);

            if (!validationResult.IsValid)
            {
                return(BadRequest(validationResult.Message));
            }

            if (String.IsNullOrEmpty(systemFilter))
            {
                systemFilter = GetAssociatedOrganizationsFilter(_organizationRepository, validationResult.UsesPremiumFeatures, HasOrganizationOrProjectFilter(userFilter));
            }

            var timeInfo = GetTimeInfo(time, offset);

            ICollection <TermStatsItem> terms;

            try {
                terms = _eventStats.GetTermsStats(timeInfo.UtcRange.Start, timeInfo.UtcRange.End, "stack_id", systemFilter, userFilter, timeInfo.Offset, GetSkip(page + 1, limit) + 1).Terms;
            } catch (ApplicationException ex) {
                Log.Error().Exception(ex)
                .Property("Search Filter", new { SystemFilter = systemFilter, UserFilter = userFilter, Time = time, Offset = offset, Page = page, Limit = limit })
                .Tag("Search")
                .Property("User", ExceptionlessUser)
                .ContextProperty("HttpActionContext", ActionContext)
                .Write();

                return(BadRequest("An error has occurred. Please check your search filter."));
            }

            if (terms.Count == 0)
            {
                return(Ok(new object[0]));
            }

            var stackIds = terms.Skip(skip).Take(limit + 1).Select(t => t.Term).ToArray();
            var stacks   = _stackRepository.GetByIds(stackIds).Select(s => s.ApplyOffset(timeInfo.Offset)).ToList();

            if (!String.IsNullOrEmpty(mode) && String.Equals(mode, "summary", StringComparison.InvariantCultureIgnoreCase))
            {
                var summaries = GetStackSummaries(stacks, terms);
                return(OkWithResourceLinks(GetStackSummaries(stacks, terms).Take(limit).ToList(), summaries.Count > limit, page));
            }

            return(OkWithResourceLinks(stacks.Take(limit).ToList(), stacks.Count > limit, page));
        }
コード例 #3
0
        public IHttpActionResult FrequentInternal(string systemFilter = null, string userFilter = null, string time = null, string offset = null, string mode = null, int page = 1, int limit = 10)
        {
            page  = GetPage(page);
            limit = GetLimit(limit);
            var skip = GetSkip(page, limit);

            if (skip > MAXIMUM_SKIP)
            {
                return(Ok(new object[0]));
            }

            var validationResult = QueryValidator.Validate(userFilter);

            if (!validationResult.IsValid)
            {
                return(BadRequest(validationResult.Message));
            }

            if (String.IsNullOrEmpty(systemFilter))
            {
                systemFilter = GetAssociatedOrganizationsFilter(_organizationRepository, validationResult.UsesPremiumFeatures, HasOrganizationOrProjectFilter(userFilter));
            }

            var timeInfo = GetTimeInfo(time, offset);
            var terms    = _eventStats.GetTermsStats(timeInfo.UtcRange.Start, timeInfo.UtcRange.End, "stack_id", systemFilter, userFilter, timeInfo.Offset, GetSkip(page + 1, limit) + 1).Terms;

            if (terms.Count == 0)
            {
                return(Ok(new object[0]));
            }

            var stackIds = terms.Skip(skip).Take(limit + 1).Select(t => t.Term).ToArray();
            var stacks   = _stackRepository.GetByIds(stackIds).Select(s => s.ApplyOffset(timeInfo.Offset)).ToList();

            if (!String.IsNullOrEmpty(mode) && String.Equals(mode, "summary", StringComparison.InvariantCultureIgnoreCase))
            {
                var summaries = GetStackSummaries(stacks, terms);
                return(OkWithResourceLinks(GetStackSummaries(stacks, terms).Take(limit).ToList(), summaries.Count > limit, page));
            }

            return(OkWithResourceLinks(stacks.Take(limit).ToList(), stacks.Count > limit, page));
        }
コード例 #4
0
        public void CanGetEventTermStats()
        {
            // capture start date before generating data to make sure that our time range for stats includes all items
            var       startDate  = DateTime.UtcNow.SubtractDays(60);
            const int eventCount = 10;

            RemoveData();
            CreateData(eventCount);

            _client.Refresh();
            var result = _stats.GetTermsStats(startDate, DateTime.UtcNow, "tags");

            Assert.Equal(eventCount, result.Total);
        }
コード例 #5
0
        public IHttpActionResult FrequentInternal(string systemFilter = null, string userFilter = null, string time = null, string offset = null, string mode = null, int page = 1, int limit = 10)
        {
            page  = GetPage(page);
            limit = GetLimit(limit);
            var skip = GetSkip(page, limit);

            if (skip > MAXIMUM_SKIP)
            {
                return(Ok(new object[0]));
            }

            if (String.IsNullOrEmpty(systemFilter))
            {
                systemFilter = GetAssociatedOrganizationsFilter();
            }
            var timeInfo = GetTimeInfo(time, offset);
            var terms    = _eventStats.GetTermsStats(timeInfo.UtcRange.Start, timeInfo.UtcRange.End, "stack_id", systemFilter, userFilter, timeInfo.Offset, GetSkip(page + 1, limit) + 1).Terms;

            if (terms.Count == 0)
            {
                return(Ok(new object[0]));
            }

            // TODO: Apply retention cutoff
            var stackIds = terms.Skip(skip).Take(limit + 1).Select(t => t.Term).ToArray();
            var stacks   = _stackRepository.GetByIds(stackIds).Select(s => s.ApplyOffset(timeInfo.Offset)).ToList();

            // TODO: Add header that contains the number of stacks outside of the retention period.
            if (!String.IsNullOrEmpty(mode) && String.Equals(mode, "summary", StringComparison.InvariantCultureIgnoreCase))
            {
                var summaries = GetStackSummaries(stacks, terms);
                return(OkWithResourceLinks(GetStackSummaries(stacks, terms).Take(limit).ToList(), summaries.Count > limit, page));
            }

            return(OkWithResourceLinks(stacks.Take(limit).ToList(), stacks.Count > limit, page));
        }
コード例 #6
0
        private List <ViewProject> PopulateProjectStats(List <ViewProject> projects)
        {
            if (projects.Count <= 0)
            {
                return(projects);
            }

            var           organizations = _organizationRepository.GetByIds(projects.Select(p => p.Id).ToArray(), useCache: true);
            StringBuilder builder       = new StringBuilder();

            for (int index = 0; index < projects.Count; index++)
            {
                if (index > 0)
                {
                    builder.Append(" OR ");
                }

                var project      = projects[index];
                var organization = organizations.FirstOrDefault(o => o.Id == project.Id);
                if (organization != null && organization.RetentionDays > 0)
                {
                    builder.AppendFormat("(project:{0} AND (date:[now/d-{1}d TO now/d+1d}} OR last:[now/d-{1}d TO now/d+1d}}))", project.Id, organization.RetentionDays);
                }
                else
                {
                    builder.AppendFormat("project:{0}", project.Id);
                }
            }

            var result = _stats.GetTermsStats(DateTime.MinValue, DateTime.MaxValue, "project_id", builder.ToString());

            foreach (var project in projects)
            {
                var projectStats = result.Terms.FirstOrDefault(t => t.Term == project.Id);
                project.EventCount = projectStats != null ? projectStats.Total : 0;
                project.StackCount = projectStats != null ? projectStats.Unique : 0;
            }

            return(projects);
        }
コード例 #7
0
        private List <ViewOrganization> PopulateOrganizationStats(List <ViewOrganization> organizations)
        {
            if (organizations.Count <= 0)
            {
                return(organizations);
            }

            StringBuilder builder = new StringBuilder();

            for (int index = 0; index < organizations.Count; index++)
            {
                if (index > 0)
                {
                    builder.Append(" OR ");
                }

                var organization = organizations[index];
                if (organization.RetentionDays > 0)
                {
                    builder.AppendFormat("(organization:{0} AND (date:[now/d-{1}d TO now/d+1d}} OR last:[now/d-{1}d TO now/d+1d}}))", organization.Id, organization.RetentionDays);
                }
                else
                {
                    builder.AppendFormat("organization:{0}", organization.Id);
                }
            }

            var result = _stats.GetTermsStats(DateTime.MinValue, DateTime.MaxValue, "organization_id", builder.ToString());

            foreach (var organization in organizations)
            {
                var organizationStats = result.Terms.FirstOrDefault(t => t.Term == organization.Id);
                organization.EventCount   = organizationStats != null ? organizationStats.Total : 0;
                organization.StackCount   = organizationStats != null ? organizationStats.Unique : 0;
                organization.ProjectCount = _projectRepository.GetByOrganizationId(organization.Id, useCache: true).Count;
            }

            return(organizations);
        }
コード例 #8
0
        private void ProcessSummaryNotification(SummaryNotification data)
        {
            var project      = _projectRepository.GetById(data.Id, true);
            var organization = _organizationRepository.GetById(project.OrganizationId, true);
            var userIds      = project.NotificationSettings.Where(n => n.Value.SendDailySummary).Select(n => n.Key).ToList();

            if (userIds.Count == 0)
            {
                return;
            }

            var users = _userRepository.GetByIds(userIds).Where(u => u.IsEmailAddressVerified).ToList();

            if (users.Count == 0)
            {
                return;
            }

            long count;
            var  paging = new PagingOptions {
                Limit = 5
            };
            List <Stack> newest = _stackRepository.GetNew(project.Id, data.UtcStartTime, data.UtcEndTime, paging).ToList();

            var result       = _stats.GetTermsStats(data.UtcStartTime, data.UtcEndTime, "stack_id", "project:" + data.Id, max: 5);
            var mostFrequent = result.Terms.Take(5).ToList();
            var stacks       = _stackRepository.GetByIds(mostFrequent.Select(s => s.Term).ToList());

            foreach (var frequent in mostFrequent)
            {
                var stack = stacks.SingleOrDefault(s => s.Id == frequent.Term);
                if (stack == null)
                {
                    mostFrequent.RemoveAll(r => r.Term == frequent.Term);
                    continue;
                }

                // Stat's Id and Total properties are already calculated in the Results.
                //frequent.Type = stack.SignatureInfo.ContainsKey("ExceptionType") ? stack.SignatureInfo["ExceptionType"] : null;
                //frequent.Method = stack.SignatureInfo.ContainsKey("Method") ? stack.SignatureInfo["Method"] : null;
                //frequent.Path = stack.SignatureInfo.ContainsKey("Path") ? stack.SignatureInfo["Path"] : null;
                //frequent.Is404 = stack.SignatureInfo.ContainsKey("Path");

                //frequent.Title = stack.Title;
                //frequent.First = stack.FirstOccurrence;
                //frequent.Last = stack.LastOccurrence;
            }

            var notification = new SummaryNotificationModel {
                ProjectId   = project.Id,
                ProjectName = project.Name,
                StartDate   = data.UtcStartTime,
                EndDate     = data.UtcEndTime,
                //Total = result.Total,
                //PerHourAverage = result.PerHourAverage,
                //NewTotal = result.NewTotal,
                //New = newest,
                //UniqueTotal = result.UniqueTotal,
                //MostFrequent = mostFrequent,
                //HasSubmittedErrors = project.TotalErrorCount > 0,
                IsFreePlan = organization.PlanId == BillingManager.FreePlan.Id
            };

            foreach (var user in users.Where(u => u.EmailNotificationsEnabled))
            {
                _mailer.SendSummaryNotification(user.EmailAddress, notification);
            }
        }
コード例 #9
0
        private void ProcessSummaryNotification(SummaryNotification data)
        {
            var project      = _projectRepository.GetById(data.Id, true);
            var organization = _organizationRepository.GetById(project.OrganizationId, true);
            var userIds      = project.NotificationSettings.Where(n => n.Value.SendDailySummary).Select(n => n.Key).ToList();

            if (userIds.Count == 0)
            {
                Log.Info().Message("Project \"{0}\" has no users to send summary to.", project.Id).Write();
                return;
            }

            var users = _userRepository.GetByIds(userIds).Where(u => u.IsEmailAddressVerified && u.EmailNotificationsEnabled && u.OrganizationIds.Contains(organization.Id)).ToList();

            if (users.Count == 0)
            {
                Log.Info().Message("Project \"{0}\" has no users to send summary to.", project.Id).Write();
                return;
            }

            Log.Info().Message("Sending daily summary: users={0} project={1}", users.Count, project.Id).Write();
            var paging = new PagingOptions {
                Limit = 5
            };
            List <Stack> newest = _stackRepository.GetNew(project.Id, data.UtcStartTime, data.UtcEndTime, paging).ToList();

            var result = _stats.GetTermsStats(data.UtcStartTime, data.UtcEndTime, "stack_id", "type:error project:" + data.Id, max: 5);
            //var termStatsList = result.Terms.Take(5).ToList();
            //var stacks = _stackRepository.GetByIds(termStatsList.Select(s => s.Term).ToList());
            bool hasSubmittedErrors = result.Total > 0;

            if (!hasSubmittedErrors)
            {
                hasSubmittedErrors = _eventRepository.GetCountByProjectId(project.Id) > 0;
            }

            var mostFrequent = new List <EventStackResult>();
            //foreach (var termStats in termStatsList) {
            //    var stack = stacks.SingleOrDefault(s => s.Id == termStats.Term);
            //    if (stack == null)
            //        continue;

            //    mostFrequent.Add(new EventStackResult {
            //        First =  termStats.FirstOccurrence,
            //        Last = termStats.LastOccurrence,
            //        Id = stack.Id,
            //        Title = stack.Title,
            //        Total = termStats.Total,
            //        Type = stack.SignatureInfo.ContainsKey("ExceptionType") ? stack.SignatureInfo["ExceptionType"] : null,
            //        Method = stack.SignatureInfo.ContainsKey("Method") ? stack.SignatureInfo["Method"] : null,
            //        Path = stack.SignatureInfo.ContainsKey("Source") ? stack.SignatureInfo["Source"] : null,
            //        Is404 = stack.SignatureInfo.ContainsKey("Type") && stack.SignatureInfo["Type"] == "404"
            //    });
            //}

            var notification = new DailySummaryModel {
                ProjectId          = project.Id,
                ProjectName        = project.Name,
                StartDate          = data.UtcStartTime,
                EndDate            = data.UtcEndTime,
                Total              = result.Total,
                PerHourAverage     = result.Total / data.UtcEndTime.Subtract(data.UtcStartTime).TotalHours,
                NewTotal           = result.New,
                New                = newest,
                UniqueTotal        = result.Unique,
                MostFrequent       = mostFrequent,
                HasSubmittedEvents = hasSubmittedErrors,
                IsFreePlan         = organization.PlanId == BillingManager.FreePlan.Id
            };

            foreach (var user in users)
            {
                _mailer.SendDailySummary(user.EmailAddress, notification);
            }

            Log.Info().Message("Done sending daily summary: users={0} project={1} events={2}", users.Count, project.Id, notification.Total).Write();
        }