rda-python-metrics 3.0.5__tar.gz → 3.0.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rda_python_metrics-3.0.5/src/rda_python_metrics.egg-info → rda_python_metrics-3.0.7}/PKG-INFO +1 -1
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/pyproject.toml +1 -1
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillawsusage.py +5 -2
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillcdgusage.py +4 -1
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillcodusage.py +6 -3
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillgdexusage.py +4 -1
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillglobususage.py +5 -2
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillipinfo.py +4 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillosdfusage.py +28 -9
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/filltdsusage.py +5 -2
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillzenodousage.py +4 -1
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/pg_ipinfo.py +131 -12
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7/src/rda_python_metrics.egg-info}/PKG-INFO +1 -1
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/LICENSE +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/MANIFEST.in +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/README.md +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/setup.cfg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/PgIPInfo.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/PgView.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/__init__.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_awsusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_cdgusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_codusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_country.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_endtime.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_globususage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_ipinfo.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_oneorder.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_osdfusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_rdadb.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_tdsusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillawsusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillcdgusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillcodusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillcountry.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillendtime.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillgdexusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillglobususage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillipinfo.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/filloneorder.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/filloneorder.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillosdfusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillrdadb.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillrdadb.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/filltdsusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillzenodousage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/log_arch.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/logarch.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/logarch.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/pg_view.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/pgsyspath.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_allusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_awsusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_checkusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_codusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_ordusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_osdfusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_rqstusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_tdsusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_webfile.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_webusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewallusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewallusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewawsusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewawsusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewcheckusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewcheckusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewcodusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewcodusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewordusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewordusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewosdfusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewosdfusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewrqstusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewrqstusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewtdsusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewtdsusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewwebfile.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewwebfile.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewwebusage.py +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewwebusage.usg +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics.egg-info/SOURCES.txt +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics.egg-info/dependency_links.txt +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics.egg-info/entry_points.txt +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics.egg-info/requires.txt +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics.egg-info/top_level.txt +0 -0
- {rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/tests/test_metrics.py +0 -0
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillawsusage.py
RENAMED
|
@@ -107,6 +107,7 @@ class FillAWSUsage(PgIPInfo, PgFile):
|
|
|
107
107
|
for logfile in fnames:
|
|
108
108
|
aws = self.open_local_file(logfile)
|
|
109
109
|
if not aws: continue
|
|
110
|
+
self.prescan_ips(aws, r'^\w+ [\w-]+ \[[^\]]*\] ([\da-fA-F.:]+) ')
|
|
110
111
|
while True:
|
|
111
112
|
line = aws.readline()
|
|
112
113
|
if not line: break
|
|
@@ -114,13 +115,15 @@ class FillAWSUsage(PgIPInfo, PgFile):
|
|
|
114
115
|
if entcnt%20000 == 0:
|
|
115
116
|
dcnt = len(records)
|
|
116
117
|
self.pglog("{}: {}/{} AWS log entries processed/records to add".format(pdate, entcnt, dcnt), self.WARNLG)
|
|
117
|
-
|
|
118
|
+
# the ip field holds an IPv6 address as well as an IPv4 one
|
|
119
|
+
ms = re.match(r'^\w+ ([\w-]+) \[(\S+).*\] ([\da-fA-F.:]+) .+ REST\.GET\.OBJECT \S+ "GET.+" \d+ - (\d+) \d+ .* ".+" "(.+)" ', line)
|
|
118
120
|
if not ms: continue
|
|
119
121
|
values = list(ms.groups())
|
|
120
122
|
if values[0] not in self.DSIDS: continue
|
|
121
123
|
dsid = self.DSIDS[values[0]]
|
|
122
124
|
size = int(values[3])
|
|
123
|
-
ip = values[2]
|
|
125
|
+
ip = self.normalize_ip(values[2])
|
|
126
|
+
if not ip: continue
|
|
124
127
|
engine = values[4]
|
|
125
128
|
moff = engine.find('/')
|
|
126
129
|
if moff > 0:
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillcdgusage.py
RENAMED
|
@@ -204,6 +204,8 @@ class FillCDGUsage(PgSplit, PgIPInfo):
|
|
|
204
204
|
self.pglog("{}: Query for {} CDG dsid/subdsids between {} and {} at {}".format(strids, dscnt, dates[0], dates[1], self.current_datetime()), self.LOGWRN)
|
|
205
205
|
pgrecs = self.pgmget(tbname, fields, cond)
|
|
206
206
|
self.dssdb_dbname()
|
|
207
|
+
# back on dssdb, where table ipinfo is, before presolving the host names
|
|
208
|
+
if pgrecs: self.preset_ip_hostnames(pgrecs['remote_address'])
|
|
207
209
|
return pgrecs
|
|
208
210
|
|
|
209
211
|
def fill_cdg_usages(self, dsids, dranges):
|
|
@@ -243,7 +245,8 @@ class FillCDGUsage(PgSplit, PgIPInfo):
|
|
|
243
245
|
(year, quarter, date, time) = self.get_record_date_time(pgrec['date_completed'])
|
|
244
246
|
url = pgrec['dataset_file_file_access_point_uri']
|
|
245
247
|
if not url: url = pgrec['file_access_point_uri']
|
|
246
|
-
ip = pgrec['remote_address']
|
|
248
|
+
ip = self.normalize_ip(pgrec['remote_address'])
|
|
249
|
+
if not ip: continue
|
|
247
250
|
engine = pgrec['user_agent_name']
|
|
248
251
|
ms = re.search(r'^https*://tds.ucar.edu/thredds/(\w+)/', url)
|
|
249
252
|
if ms:
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillcodusage.py
RENAMED
|
@@ -116,9 +116,11 @@ class FillCODUsage(PgIPInfo):
|
|
|
116
116
|
size = int(ms.group(2))
|
|
117
117
|
engine = ms.group(3)
|
|
118
118
|
if not (aid in self.USERS or self.cache_users(aid)): continue
|
|
119
|
-
|
|
119
|
+
# the ip field holds an IPv6 address as well as an IPv4 one
|
|
120
|
+
ms = re.match(r'^([\da-fA-F.:]+).+\[(\d+)/(\w+)/(\d+):([\d:]+)', line)
|
|
120
121
|
if not ms: continue
|
|
121
|
-
ip = ms.group(1)
|
|
122
|
+
ip = self.normalize_ip(ms.group(1))
|
|
123
|
+
if not ip: continue
|
|
122
124
|
ctime = ms.group(5)
|
|
123
125
|
cdate = "{}-{:02}-{:02}".format(ms.group(4), self.get_month(ms.group(3)), int(ms.group(2)))
|
|
124
126
|
if pdate != cdate:
|
|
@@ -153,6 +155,7 @@ class FillCODUsage(PgIPInfo):
|
|
|
153
155
|
year = ms.group(1)
|
|
154
156
|
quarter = 1 + int((int(ms.group(2)) - 1) / 3)
|
|
155
157
|
cnt = 0
|
|
158
|
+
self.preset_ip_hostnames([records[aid]['ip'] for aid in records])
|
|
156
159
|
for aid in records:
|
|
157
160
|
if self.pgget(self.USAGE['PGTBL'], '', "aid = '{}' AND date = '{}'".format(aid, date), self.LGEREX): continue
|
|
158
161
|
record = records[aid]
|
|
@@ -162,7 +165,7 @@ class FillCODUsage(PgIPInfo):
|
|
|
162
165
|
record['org_type'] = wurec['org_type']
|
|
163
166
|
record['country'] = wurec['country']
|
|
164
167
|
record['region'] = wurec['region']
|
|
165
|
-
record['email'] = '
|
|
168
|
+
record['email'] = wurec['email'] # already 'unknown@<hostname>' for a generic ip
|
|
166
169
|
else:
|
|
167
170
|
wuid = self.check_wuser_wuid(record['email'], date)
|
|
168
171
|
if not wuid: continue
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillgdexusage.py
RENAMED
|
@@ -857,6 +857,8 @@ class FillGDEXUsage(PgSplit, PgIPInfo):
|
|
|
857
857
|
self.pglog("{}: Query for {} GDEX dsid/subdsids between {} and {} at {}".format(strids, dscnt, dates[0], dates[1], self.current_datetime()), self.LOGWRN)
|
|
858
858
|
pgrecs = self.pgmget(tbname, fields, cond)
|
|
859
859
|
self.dssdb_dbname()
|
|
860
|
+
# back on dssdb, where table ipinfo is, before presolving the host names
|
|
861
|
+
if pgrecs: self.preset_ip_hostnames(pgrecs['remote_address'])
|
|
860
862
|
|
|
861
863
|
return pgrecs
|
|
862
864
|
|
|
@@ -892,7 +894,8 @@ class FillGDEXUsage(PgSplit, PgIPInfo):
|
|
|
892
894
|
dsize = pgrec['bytes_sent']
|
|
893
895
|
if not dsize: continue
|
|
894
896
|
(year, quarter, date, time) = self.get_record_date_time(pgrec['date_completed'])
|
|
895
|
-
ip = pgrec['remote_address']
|
|
897
|
+
ip = self.normalize_ip(pgrec['remote_address'])
|
|
898
|
+
if not ip: continue
|
|
896
899
|
engine = pgrec['user_agent_name']
|
|
897
900
|
wfile = pgrec['dataset_file_name']
|
|
898
901
|
if not wfile: wfile = pgrec['logical_file_name']
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillglobususage.py
RENAMED
|
@@ -106,6 +106,7 @@ class FillGlobusUsage(PgIPInfo, PgSplit, PgFile):
|
|
|
106
106
|
self.pglog("Gathering usage info from {} at {}".format(logfile, self.current_datetime()), self.LOGWRN)
|
|
107
107
|
globus = self.open_local_file(logfile)
|
|
108
108
|
if not globus: continue
|
|
109
|
+
self.prescan_ips(globus, r'^([\da-fA-F.:]+)\s')
|
|
109
110
|
ptime = ''
|
|
110
111
|
record = {}
|
|
111
112
|
cntadd = entcnt = 0
|
|
@@ -116,11 +117,13 @@ class FillGlobusUsage(PgIPInfo, PgSplit, PgFile):
|
|
|
116
117
|
entcnt += 1
|
|
117
118
|
if entcnt%10000 == 0:
|
|
118
119
|
self.pglog("{}: {}/{} Globus log entries processed/records added".format(logfile, entcnt, cntadd), self.WARNLG)
|
|
119
|
-
|
|
120
|
+
# the ip field holds an IPv6 address as well as an IPv4 one
|
|
121
|
+
ms = re.match(r'^([\da-fA-F.:]+)\s.*\s+\[(\S+).*"GET\s+/(ds\d\d\d\.\d|[a-z]\d{6})/(\S+)\s.*\s(200|206)\s+(\d+)\s+"(\S+)"\s+"(.+)"$', line)
|
|
120
122
|
if not ms: continue
|
|
121
123
|
size = int(ms.group(6))
|
|
122
124
|
if size < 100: continue # ignore small files
|
|
123
|
-
ip = ms.group(1)
|
|
125
|
+
ip = self.normalize_ip(ms.group(1))
|
|
126
|
+
if not ip: continue
|
|
124
127
|
dsid = self.format_dataset_id(ms.group(3))
|
|
125
128
|
wfile = ms.group(4)
|
|
126
129
|
stat = ms.group(5)
|
|
@@ -117,6 +117,7 @@ class FillIPInfo(PgIPInfo):
|
|
|
117
117
|
if not pgrecs: return 0
|
|
118
118
|
cnt = len(pgrecs['ip']) if pgrecs else 0
|
|
119
119
|
mcnt = 0
|
|
120
|
+
self.preset_ip_hostnames(pgrecs['ip'])
|
|
120
121
|
for i in range(cnt):
|
|
121
122
|
record = self.get_missing_ipinfo(pgrecs['ip'][i], pgrecs['email'][i])
|
|
122
123
|
if record: mcnt += self.pgupdt(table, record, "aidx = '{}'".format(pgrecs['aidx'][i]))
|
|
@@ -132,6 +133,7 @@ class FillIPInfo(PgIPInfo):
|
|
|
132
133
|
if not pgrecs: return 0
|
|
133
134
|
cnt = len(pgrecs['ip']) if pgrecs else 0
|
|
134
135
|
mcnt = 0
|
|
136
|
+
self.preset_ip_hostnames(pgrecs['ip'])
|
|
135
137
|
for i in range(cnt):
|
|
136
138
|
ip = pgrecs['ip'][i]
|
|
137
139
|
record = self.get_missing_ipinfo(ip, pgrecs['email'][i])
|
|
@@ -150,6 +152,7 @@ class FillIPInfo(PgIPInfo):
|
|
|
150
152
|
if not pgrecs: return 0
|
|
151
153
|
cnt = len(pgrecs['ip']) if pgrecs else 0
|
|
152
154
|
mcnt = 0
|
|
155
|
+
self.preset_ip_hostnames(pgrecs['ip'])
|
|
153
156
|
for i in range(cnt):
|
|
154
157
|
record = self.get_missing_ipinfo(pgrecs['ip'][i], pgrecs['email'][i])
|
|
155
158
|
if record:
|
|
@@ -183,6 +186,7 @@ class FillIPInfo(PgIPInfo):
|
|
|
183
186
|
if not pgrecs: return 0
|
|
184
187
|
cnt = len(pgrecs['ip']) if pgrecs else 0
|
|
185
188
|
mcnt = 0
|
|
189
|
+
self.preset_ip_hostnames(pgrecs['ip'])
|
|
186
190
|
for i in range(cnt):
|
|
187
191
|
if self.set_ipinfo(pgrecs['ip'][i]): mcnt +=1
|
|
188
192
|
s = 's' if cnt > 1 else ''
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillosdfusage.py
RENAMED
|
@@ -105,6 +105,7 @@ class FillOSDFUsage(PgIPInfo, PgFile, PgSplit):
|
|
|
105
105
|
osdf = self.open_local_file(logfile)
|
|
106
106
|
if not osdf: continue
|
|
107
107
|
records = {}
|
|
108
|
+
ips = {}
|
|
108
109
|
cntadd = entcnt = 0
|
|
109
110
|
while True:
|
|
110
111
|
line = osdf.readline()
|
|
@@ -113,13 +114,16 @@ class FillOSDFUsage(PgIPInfo, PgFile, PgSplit):
|
|
|
113
114
|
if entcnt%20000 == 0:
|
|
114
115
|
dcnt = len(records)
|
|
115
116
|
self.pglog("{}: {}/{} OSDF log entries processed/records added".format(logfile, entcnt, dcnt), self.WARNLG)
|
|
116
|
-
|
|
117
|
+
# the OSDF namespace was renamed from /ncar/rda to /ncar/gdex
|
|
118
|
+
ms = re.match(r'^\[(\S+)\] \[Objectname:\/ncar\/(?:rda|gdex)\/([a-z]\d{6})\/\S+\].* \[Site:(\S+)\].* \[Host:(\S+)\].* \[AppInfo:(\S*)\].* \[Read:(\d+)\]', line)
|
|
117
119
|
if not ms: continue
|
|
118
120
|
dt = ms.group(1)
|
|
119
121
|
dsid = ms.group(2)
|
|
120
122
|
site = ms.group(3)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
+
# normalize before keying on it, so one address spelled two ways in the
|
|
124
|
+
# log aggregates into one usage record rather than two
|
|
125
|
+
ip = self.GIP if ms.group(4) == 'N/A' else self.normalize_ip(ms.group(4))
|
|
126
|
+
if not ip: continue
|
|
123
127
|
engine = ms.group(5)
|
|
124
128
|
size = int(ms.group(6))
|
|
125
129
|
if re.match(r'^N/A', engine, re.I):
|
|
@@ -137,13 +141,13 @@ class FillOSDFUsage(PgIPInfo, PgFile, PgSplit):
|
|
|
137
141
|
records[key]['fcount'] += 1
|
|
138
142
|
else:
|
|
139
143
|
(year, quarter, date, time) = self.get_record_date_time(dt)
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
'size' : size, 'fcount' : 1, 'method' : method, 'engine' : engine,
|
|
144
|
-
'org_type' : iprec['org_type'], 'country' : iprec['country'],
|
|
145
|
-
'region' : iprec['region'], 'email' : iprec['email'], 'site' : site}
|
|
144
|
+
ips[ip] = 1
|
|
145
|
+
records[key] = {'ip' : ip, 'dsid' : dsid, 'date' : date, 'time' : time, 'quarter' : quarter,
|
|
146
|
+
'size' : size, 'fcount' : 1, 'method' : method, 'engine' : engine, 'site' : site}
|
|
146
147
|
osdf.close()
|
|
148
|
+
if records:
|
|
149
|
+
self.preset_ip_hostnames(list(ips))
|
|
150
|
+
records = self.fill_ipinfo_records(records)
|
|
147
151
|
if records: cntadd = self.add_usage_records(records, year)
|
|
148
152
|
self.pglog("{}: {} OSDF usage records added for {} entries at {}".format(logfile, cntadd, entcnt, self.current_datetime()), self.LOGWRN)
|
|
149
153
|
cntall += entcnt
|
|
@@ -165,6 +169,21 @@ class FillOSDFUsage(PgIPInfo, PgFile, PgSplit):
|
|
|
165
169
|
else:
|
|
166
170
|
self.pglog(ctime + ": Invalid date/time format", self.LGEREX)
|
|
167
171
|
|
|
172
|
+
def fill_ipinfo_records(self, records):
|
|
173
|
+
"""Add the ip info fields to the usage records; drop the ones without ip info."""
|
|
174
|
+
for key in list(records):
|
|
175
|
+
record = records[key]
|
|
176
|
+
iprec = self.get_missing_ipinfo(record['ip'])
|
|
177
|
+
if not iprec:
|
|
178
|
+
del records[key]
|
|
179
|
+
continue
|
|
180
|
+
record['ip'] = iprec['ip']
|
|
181
|
+
record['org_type'] = iprec['org_type']
|
|
182
|
+
record['country'] = iprec['country']
|
|
183
|
+
record['region'] = iprec['region']
|
|
184
|
+
record['email'] = iprec['email']
|
|
185
|
+
return records
|
|
186
|
+
|
|
168
187
|
def add_usage_records(self, records, year):
|
|
169
188
|
"""Add usage to table osdfusage."""
|
|
170
189
|
cnt = 0
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/filltdsusage.py
RENAMED
|
@@ -115,6 +115,7 @@ class FillTDSUsage(PgIPInfo, PgFile):
|
|
|
115
115
|
self.pglog("{}: Gathering TDS usage at {}".format(logfile, self.current_datetime()), self.LOGWRN)
|
|
116
116
|
tds = self.open_local_file(logfile)
|
|
117
117
|
if not tds: continue
|
|
118
|
+
self.prescan_ips(tds, r'^([\da-fA-F.:]+)\s')
|
|
118
119
|
records = {}
|
|
119
120
|
cntadd = entcnt = 0
|
|
120
121
|
while True:
|
|
@@ -128,7 +129,8 @@ class FillTDSUsage(PgIPInfo, PgFile):
|
|
|
128
129
|
if ms: continue
|
|
129
130
|
ms = re.search(r'/thredds/\S+\.(png|jpg|gif|css|htm)', line)
|
|
130
131
|
if ms: continue
|
|
131
|
-
|
|
132
|
+
# the ip field holds an IPv6 address as well as an IPv4 one
|
|
133
|
+
ms = re.match(r'^([\da-fA-F.:]+)\s.*\s(-|\S+@\S+)\s+\[(\S+).*/thredds/(\w+)(/|/grid/)(aggregations|files).*/(ds\d\d\d.\d|[a-z]\d{6})/.*\s200\s+(\d+)(.*)$', line)
|
|
132
134
|
if not ms: continue
|
|
133
135
|
ip = ms.group(1)
|
|
134
136
|
email = ms.group(2)
|
|
@@ -178,6 +180,7 @@ class FillTDSUsage(PgIPInfo, PgFile):
|
|
|
178
180
|
if ms:
|
|
179
181
|
year = ms.group(1)
|
|
180
182
|
quarter = 1 + int((int(ms.group(2)) - 1)/3)
|
|
183
|
+
self.preset_ip_hostnames([records[key]['ip'] for key in records])
|
|
181
184
|
for key in records:
|
|
182
185
|
record = records[key]
|
|
183
186
|
cond = "date = '{}' AND time = '{}' AND ip = '{}' AND dsid = '{}'".format(date, record['time'], record['ip'], record['dsid'])
|
|
@@ -189,7 +192,7 @@ class FillTDSUsage(PgIPInfo, PgFile):
|
|
|
189
192
|
record['org_type'] = wurec['org_type']
|
|
190
193
|
record['country'] = wurec['country']
|
|
191
194
|
record['region'] = wurec['region']
|
|
192
|
-
record['email'] = '
|
|
195
|
+
record['email'] = wurec['email'] # already 'unknown@<hostname>' for a generic ip
|
|
193
196
|
record['quarter'] = quarter
|
|
194
197
|
record['date'] = date
|
|
195
198
|
if self.add_to_allusage(year, record):
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillzenodousage.py
RENAMED
|
@@ -284,6 +284,8 @@ class FillZenodoUsage(PgSplit, PgIPInfo):
|
|
|
284
284
|
self.pglog("{}: Query for {} GDEX dsid/subdsids between {} and {} at {}".format(strids, dscnt, dates[0], dates[1], self.current_datetime()), self.LOGWRN)
|
|
285
285
|
pgrecs = self.pgmget(tbname, fields, cond)
|
|
286
286
|
self.dssdb_dbname()
|
|
287
|
+
# back on dssdb, where table ipinfo is, before presolving the host names
|
|
288
|
+
if pgrecs: self.preset_ip_hostnames(pgrecs['remote_address'])
|
|
287
289
|
|
|
288
290
|
return pgrecs
|
|
289
291
|
|
|
@@ -322,7 +324,8 @@ class FillZenodoUsage(PgSplit, PgIPInfo):
|
|
|
322
324
|
(year, quarter, date, time) = self.get_record_date_time(pgrec['date_completed'])
|
|
323
325
|
url = pgrec['dataset_file_file_access_point_uri']
|
|
324
326
|
if not url: url = pgrec['file_access_point_uri']
|
|
325
|
-
ip = pgrec['remote_address']
|
|
327
|
+
ip = self.normalize_ip(pgrec['remote_address'])
|
|
328
|
+
if not ip: continue
|
|
326
329
|
engine = pgrec['user_agent_name']
|
|
327
330
|
ms = re.search(r'^https*://tds.ucar.edu/thredds/(\w+)/', url)
|
|
328
331
|
if ms:
|
|
@@ -12,9 +12,12 @@
|
|
|
12
12
|
import re
|
|
13
13
|
import geoip2.database as geodb
|
|
14
14
|
import ipinfo
|
|
15
|
-
import
|
|
15
|
+
from ipinfo.exceptions import RequestQuotaExceededError
|
|
16
16
|
import dns.resolver
|
|
17
|
+
import dns.reversename
|
|
17
18
|
import json
|
|
19
|
+
import ipaddress
|
|
20
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
18
21
|
from rda_python_common.pg_dbi import PgDBI
|
|
19
22
|
from rda_python_common.pg_util import PgUtil
|
|
20
23
|
|
|
@@ -30,7 +33,11 @@ class PgIPInfo(PgUtil, PgDBI):
|
|
|
30
33
|
'DBFILE' : self.PGLOG['DSSHOME'] + '/dssdb/GeoLite2-City.mmdb',
|
|
31
34
|
'CDATE' : self.curdate(),
|
|
32
35
|
'IPUPDT' : 0,
|
|
33
|
-
'IPADD' : 0
|
|
36
|
+
'IPADD' : 0,
|
|
37
|
+
'QUOTA' : 1, # unset when the ipinfo monthly request quota is used up
|
|
38
|
+
'DNSTMO' : 1, # seconds to wait on a single name server
|
|
39
|
+
'DNSLTM' : 2, # seconds to spend on one name resolution in total
|
|
40
|
+
'DNSTHD' : 8 # number of threads used to presolve a list of ip addresses
|
|
34
41
|
}
|
|
35
42
|
self.GIP = '0.0.0.0'
|
|
36
43
|
self.IPDNS = None
|
|
@@ -38,11 +45,34 @@ class PgIPInfo(PgUtil, PgDBI):
|
|
|
38
45
|
self.G2DB = None
|
|
39
46
|
self.IPRECS = {}
|
|
40
47
|
self.DMRECS = {}
|
|
48
|
+
self.IPDMS = {}
|
|
49
|
+
self.IPNRM = {}
|
|
41
50
|
self.COUNTRIES = {}
|
|
42
51
|
|
|
52
|
+
def normalize_ip(self, ip):
|
|
53
|
+
"""Return the canonical form of an ip address; empty string if it is not valid.
|
|
54
|
+
|
|
55
|
+
One IPv6 address can be written several ways, upper or lower case and with the
|
|
56
|
+
zero groups spelled out or collapsed, and the IPv4-embedded form is longer than
|
|
57
|
+
the 39 characters ipinfo.ip holds. Canonicalizing on the way in keeps one row
|
|
58
|
+
and one set of usage records per address whichever way a log spells it.
|
|
59
|
+
"""
|
|
60
|
+
if ip in self.IPNRM: return self.IPNRM[ip]
|
|
61
|
+
try:
|
|
62
|
+
nip = ipaddress.ip_address(ip).compressed
|
|
63
|
+
except ValueError:
|
|
64
|
+
self.pglog("{}: invalid ip address".format(ip), self.LOGWRN)
|
|
65
|
+
nip = ''
|
|
66
|
+
self.IPNRM[ip] = nip
|
|
67
|
+
return nip
|
|
68
|
+
|
|
43
69
|
def get_dns_resolver(self, forceget = False):
|
|
44
70
|
"""Get save a global dns.resolver.Resolver object."""
|
|
45
|
-
if forceget or not self.IPDNS:
|
|
71
|
+
if forceget or not self.IPDNS:
|
|
72
|
+
self.IPDNS = dns.resolver.Resolver()
|
|
73
|
+
self.IPDNS.timeout = self.IPINFO['DNSTMO']
|
|
74
|
+
self.IPDNS.lifetime = self.IPINFO['DNSLTM']
|
|
75
|
+
self.IPDNS.cache = dns.resolver.Cache()
|
|
46
76
|
return self.IPDNS
|
|
47
77
|
|
|
48
78
|
def dns_to_ip(self, dmname, type = 'A'):
|
|
@@ -89,32 +119,118 @@ class PgIPInfo(PgUtil, PgDBI):
|
|
|
89
119
|
if ips: return self.set_ipinfo(ips[0])
|
|
90
120
|
return None
|
|
91
121
|
|
|
122
|
+
def reverse_resolve_ip(self, ip):
|
|
123
|
+
"""Reverse resolve one ip address without logging; called from worker threads too.
|
|
124
|
+
|
|
125
|
+
Returns tuple (ip, hostname, errmsg); hostname is empty if the ip has no PTR record.
|
|
126
|
+
"""
|
|
127
|
+
try:
|
|
128
|
+
answers = self.IPDNS.resolve(dns.reversename.from_address(ip), 'PTR')
|
|
129
|
+
# an ip may have several PTR records, answered in varying order; always pick
|
|
130
|
+
# the same one so the host name on file does not flip between runs
|
|
131
|
+
if answers: return (ip, min([str(a).rstrip('.') for a in answers]), None)
|
|
132
|
+
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
|
133
|
+
pass # no PTR record on file for the ip, too common to be worth logging
|
|
134
|
+
except dns.exception.DNSException as e:
|
|
135
|
+
return (ip, '', "{}: error reverse domain name request: {}".format(ip, e))
|
|
136
|
+
return (ip, '', None)
|
|
137
|
+
|
|
138
|
+
def ip_to_dns(self, ip):
|
|
139
|
+
"""Reverse resolve an ip address to a host name; empty string if none."""
|
|
140
|
+
if ip in self.IPDMS: return self.IPDMS[ip]
|
|
141
|
+
self.get_dns_resolver()
|
|
142
|
+
(ip, dm, errmsg) = self.reverse_resolve_ip(ip)
|
|
143
|
+
if errmsg: self.pglog(errmsg, self.LOGWRN)
|
|
144
|
+
self.IPDMS[ip] = dm
|
|
145
|
+
return dm
|
|
146
|
+
|
|
147
|
+
def prescan_ips(self, fd, pattern, group = 1):
|
|
148
|
+
"""Scan an open log file for ip addresses, presolve them, and rewind the file.
|
|
149
|
+
|
|
150
|
+
A fill program reads its log line by line and looks each new ip up as it goes,
|
|
151
|
+
which serializes one slow reverse DNS lookup per address. Picking the addresses
|
|
152
|
+
out in a first cheap pass lets preset_ip_hostnames() resolve them several at a
|
|
153
|
+
time, so the main loop finds the host names already cached.
|
|
154
|
+
"""
|
|
155
|
+
ips = {}
|
|
156
|
+
for line in fd:
|
|
157
|
+
ms = re.match(pattern, line)
|
|
158
|
+
if ms: ips[ms.group(group)] = 1
|
|
159
|
+
fd.seek(0)
|
|
160
|
+
return self.preset_ip_hostnames(list(ips))
|
|
161
|
+
|
|
162
|
+
def get_recorded_ips(self, ips):
|
|
163
|
+
"""Return a dict of the given ip addresses that have an ipinfo record on file."""
|
|
164
|
+
recorded = {}
|
|
165
|
+
for i in range(0, len(ips), 1000):
|
|
166
|
+
vals = ', '.join(["'{}'".format(ip) for ip in ips[i:i+1000]])
|
|
167
|
+
pgrecs = self.pgmget('ipinfo', 'ip', "ip IN ({})".format(vals), self.LOGWRN)
|
|
168
|
+
if pgrecs:
|
|
169
|
+
for ip in pgrecs['ip']: recorded[ip] = 1
|
|
170
|
+
return recorded
|
|
171
|
+
|
|
172
|
+
def preset_ip_hostnames(self, ips):
|
|
173
|
+
"""Reverse resolve a list of ip addresses in parallel and cache the host names.
|
|
174
|
+
|
|
175
|
+
Resolving one ip at a time is the slowest part of gathering usage from a large
|
|
176
|
+
log file. Doing the new ones up front, several at a time, leaves the host names
|
|
177
|
+
in self.IPDMS for get_ip_hostname() to pick up without waiting again.
|
|
178
|
+
"""
|
|
179
|
+
ips = [ip for ip in {self.normalize_ip(ip) for ip in ips} if ip and ip not in self.IPDMS]
|
|
180
|
+
if not ips: return 0
|
|
181
|
+
# ips on file are either reused as is or refreshed by ipinfo, which carries its
|
|
182
|
+
# own host name, so only the ones not on file are worth resolving ahead of time
|
|
183
|
+
recorded = self.get_recorded_ips(ips)
|
|
184
|
+
newips = [ip for ip in ips if ip not in recorded]
|
|
185
|
+
if not newips: return 0
|
|
186
|
+
self.get_dns_resolver() # create the shared resolver before starting the threads
|
|
187
|
+
cnt = 0
|
|
188
|
+
with ThreadPoolExecutor(max_workers = self.IPINFO['DNSTHD']) as executor:
|
|
189
|
+
for (ip, dm, errmsg) in executor.map(self.reverse_resolve_ip, newips):
|
|
190
|
+
if errmsg: self.pglog(errmsg, self.LOGWRN)
|
|
191
|
+
self.IPDMS[ip] = dm
|
|
192
|
+
if dm: cnt += 1
|
|
193
|
+
self.pglog("{}/{} host names presolved for {} IP addresses".format(cnt, len(newips), len(ips)), self.LOGWRN)
|
|
194
|
+
return cnt
|
|
195
|
+
|
|
92
196
|
def get_ip_hostname(self, ip, iprec, record):
|
|
93
|
-
"""Try to get hostname via
|
|
197
|
+
"""Try to get hostname via reverse DNS for given ip address."""
|
|
94
198
|
record['hostname'] = ip
|
|
95
199
|
if iprec:
|
|
96
200
|
if 'hostname' in iprec and iprec['hostname']:
|
|
97
|
-
record['hostname'] = iprec['hostname']
|
|
201
|
+
record['hostname'] = iprec['hostname']
|
|
98
202
|
record['org_type'] = self.get_org_type(None, record['hostname'])
|
|
99
203
|
return
|
|
100
204
|
if 'asn' in iprec and iprec['asn'] and 'domain' in iprec['asn'] and iprec['asn']['domain']:
|
|
101
205
|
record['hostname'] += '.' + iprec['asn']['domain']
|
|
102
206
|
record['org_type'] = self.get_org_type(None, record['hostname'])
|
|
103
207
|
return
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
record['hostname'] =
|
|
107
|
-
record['org_type'] = self.get_org_type(None,
|
|
108
|
-
|
|
109
|
-
|
|
208
|
+
dm = self.ip_to_dns(ip)
|
|
209
|
+
if dm:
|
|
210
|
+
record['hostname'] = dm
|
|
211
|
+
record['org_type'] = self.get_org_type(None, dm)
|
|
212
|
+
|
|
213
|
+
def unset_ipinfo_quota(self):
|
|
214
|
+
"""Stop calling ipinfo for the rest of the run once its quota is used up."""
|
|
215
|
+
if self.IPINFO['QUOTA']:
|
|
216
|
+
self.IPINFO['QUOTA'] = 0
|
|
217
|
+
self.pglog("ipinfo: monthly request quota used up, use geoip2 for the rest of the run", self.LOGWRN)
|
|
110
218
|
|
|
111
219
|
def get_ipinfo_record(self, ip):
|
|
112
220
|
"""Get a ipinfo record for given ip address."""
|
|
221
|
+
if not self.IPINFO['QUOTA']: return None
|
|
113
222
|
if not self.IPDB: self.set_ipinfo_database()
|
|
114
223
|
try:
|
|
115
224
|
iprec = self.IPDB.getDetails(ip).all
|
|
225
|
+
except RequestQuotaExceededError:
|
|
226
|
+
self.unset_ipinfo_quota()
|
|
227
|
+
return None
|
|
116
228
|
except Exception as e:
|
|
117
|
-
|
|
229
|
+
estr = str(e)
|
|
230
|
+
if re.search(r'(\b429\b|quota)', estr, re.I):
|
|
231
|
+
self.unset_ipinfo_quota()
|
|
232
|
+
else:
|
|
233
|
+
self.pglog("ipinfo: {} - {}".format(ip, estr), self.LOGWRN)
|
|
118
234
|
return None
|
|
119
235
|
if 'bogon' in iprec and iprec['bogon']:
|
|
120
236
|
self.pglog(f"ipinfo: {ip} - bogon, use {self.GIP}", self.LOGWRN)
|
|
@@ -195,7 +311,10 @@ class PgIPInfo(PgUtil, PgDBI):
|
|
|
195
311
|
|
|
196
312
|
def set_ipinfo(self, ip, ipopt = True):
|
|
197
313
|
"""If ipopt is True; otherwise, use module geoip2."""
|
|
314
|
+
ip = self.normalize_ip(ip)
|
|
315
|
+
if not ip: return None
|
|
198
316
|
if ip in self.IPRECS: return self.IPRECS[ip]
|
|
317
|
+
if ipopt and not self.IPINFO['QUOTA']: ipopt = False # quota used up, geoip2 only
|
|
199
318
|
pgrec = self.pgget('ipinfo', '*', "ip = '{}'".format(ip))
|
|
200
319
|
if not pgrec or ipopt and pgrec['stat_flag'] == 'M':
|
|
201
320
|
record = self.get_ipinfo_record(ip) if ipopt else None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_awsusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_cdgusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_codusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_country.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_endtime.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_globususage.py
RENAMED
|
File without changes
|
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_oneorder.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_osdfusage.py
RENAMED
|
File without changes
|
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fill_tdsusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillawsusage.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillcdgusage.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillcodusage.usg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillgdexusage.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillglobususage.usg
RENAMED
|
File without changes
|
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/filloneorder.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/filloneorder.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillosdfusage.usg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/filltdsusage.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/fillzenodousage.usg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_allusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_awsusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_checkusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_codusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_ordusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_osdfusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_rqstusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_tdsusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_webfile.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/view_webusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewallusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewallusage.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewawsusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewawsusage.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewcheckusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewcheckusage.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewcodusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewcodusage.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewordusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewordusage.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewosdfusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewosdfusage.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewrqstusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewrqstusage.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewtdsusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewtdsusage.usg
RENAMED
|
File without changes
|
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewwebfile.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewwebusage.py
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics/viewwebusage.usg
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics.egg-info/requires.txt
RENAMED
|
File without changes
|
{rda_python_metrics-3.0.5 → rda_python_metrics-3.0.7}/src/rda_python_metrics.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|