-
Notifications
You must be signed in to change notification settings - Fork 344
/
Copy pathreports.py
170 lines (127 loc) · 5.35 KB
/
reports.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
from django.dispatch import receiver
from elasticsearch_dsl import InnerDoc
from elasticsearch_metrics import metrics
from elasticsearch_metrics.signals import pre_save as metrics_pre_save
from osf.metrics.utils import stable_key, YearMonth
class ReportInvalid(Exception):
"""Tried to save a report with invalid something-or-other
"""
pass
class DailyReport(metrics.Metric):
"""DailyReport (abstract base for report-based metrics)
There's something we'd like to know about every so often,
so let's regularly run a report and stash the results here.
"""
DAILY_UNIQUE_FIELD = None # set in subclasses that expect multiple reports per day
report_date = metrics.Date(format='strict_date', required=True)
class Meta:
abstract = True
dynamic = metrics.MetaField('strict')
source = metrics.MetaField(enabled=True)
class MonthlyReport(metrics.Metric):
"""MonthlyReport (abstract base for report-based metrics that run monthly)
"""
report_yearmonth = metrics.Date(format='strict_year_month', required=True)
class Meta:
abstract = True
dynamic = metrics.MetaField('strict')
source = metrics.MetaField(enabled=True)
@receiver(metrics_pre_save)
def set_report_id(sender, instance, **kwargs):
# Set the document id to a hash of "unique together"
# values (just `report_date` by default) to get
# "ON CONFLICT UPDATE" behavior -- if the document
# already exists, it will be updated rather than duplicated.
# Cannot detect/avoid conflicts this way, but that's ok.
if issubclass(sender, DailyReport):
duf_name = instance.DAILY_UNIQUE_FIELD
if duf_name is None:
instance.meta.id = stable_key(instance.report_date)
else:
duf_value = getattr(instance, duf_name)
if not duf_value or not isinstance(duf_value, str):
raise ReportInvalid(f'{sender.__name__}.{duf_name} MUST have a non-empty string value (got {duf_value})')
instance.meta.id = stable_key(instance.report_date, duf_value)
elif issubclass(sender, MonthlyReport):
instance.meta.id = stable_key(instance.report_yearmonth)
#### BEGIN reusable inner objects #####
class RunningTotal(InnerDoc):
total = metrics.Integer()
total_daily = metrics.Integer()
class FileRunningTotals(InnerDoc):
total = metrics.Integer()
public = metrics.Integer()
private = metrics.Integer()
total_daily = metrics.Integer()
public_daily = metrics.Integer()
private_daily = metrics.Integer()
class NodeRunningTotals(InnerDoc):
total = metrics.Integer()
total_excluding_spam = metrics.Integer()
public = metrics.Integer()
private = metrics.Integer()
total_daily = metrics.Integer()
total_daily_excluding_spam = metrics.Integer()
public_daily = metrics.Integer()
private_daily = metrics.Integer()
class RegistrationRunningTotals(InnerDoc):
total = metrics.Integer()
public = metrics.Integer()
embargoed = metrics.Integer()
embargoed_v2 = metrics.Integer()
withdrawn = metrics.Integer()
total_daily = metrics.Integer()
public_daily = metrics.Integer()
embargoed_daily = metrics.Integer()
embargoed_v2_daily = metrics.Integer()
withdrawn_daily = metrics.Integer()
##### END reusable inner objects #####
# TODO:
# class ActiveUsersReport(DailyReport):
# past_day = metrics.Integer()
# past_week = metrics.Integer()
# past_30_days = metrics.Integer()
# past_year = metrics.Integer()
class AddonUsageReport(DailyReport):
DAILY_UNIQUE_FIELD = 'addon_shortname'
addon_shortname = metrics.Keyword()
users_enabled_count = metrics.Integer()
users_authorized_count = metrics.Integer()
users_linked_count = metrics.Integer()
nodes_total_count = metrics.Integer()
nodes_connected_count = metrics.Integer()
nodes_deleted_count = metrics.Integer()
nodes_disconnected_count = metrics.Integer()
class DownloadCountReport(DailyReport):
daily_file_downloads = metrics.Integer()
class InstitutionSummaryReport(DailyReport):
DAILY_UNIQUE_FIELD = 'institution_id'
institution_id = metrics.Keyword()
institution_name = metrics.Keyword()
users = metrics.Object(RunningTotal)
nodes = metrics.Object(NodeRunningTotals)
projects = metrics.Object(NodeRunningTotals)
registered_nodes = metrics.Object(RegistrationRunningTotals)
registered_projects = metrics.Object(RegistrationRunningTotals)
class NewUserDomainReport(DailyReport):
DAILY_UNIQUE_FIELD = 'domain_name'
domain_name = metrics.Keyword()
new_user_count = metrics.Integer()
class NodeSummaryReport(DailyReport):
nodes = metrics.Object(NodeRunningTotals)
projects = metrics.Object(NodeRunningTotals)
registered_nodes = metrics.Object(RegistrationRunningTotals)
registered_projects = metrics.Object(RegistrationRunningTotals)
class OsfstorageFileCountReport(DailyReport):
files = metrics.Object(FileRunningTotals)
class PreprintSummaryReport(DailyReport):
DAILY_UNIQUE_FIELD = 'provider_key'
provider_key = metrics.Keyword()
preprint_count = metrics.Integer()
class UserSummaryReport(DailyReport):
active = metrics.Integer()
deactivated = metrics.Integer()
merged = metrics.Integer()
new_users_daily = metrics.Integer()
new_users_with_institution_daily = metrics.Integer()
unconfirmed = metrics.Integer()