rda-python-metrics 3.0.9__tar.gz → 3.0.10__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.
Files changed (87) hide show
  1. {rda_python_metrics-3.0.9/src/rda_python_metrics.egg-info → rda_python_metrics-3.0.10}/PKG-INFO +1 -1
  2. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/pyproject.toml +1 -1
  3. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillcodusage.py +43 -12
  4. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillcodusage.usg +14 -3
  5. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillglobususage.py +34 -12
  6. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillrdadb.py +75 -2
  7. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillrdadb.usg +19 -1
  8. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10/src/rda_python_metrics.egg-info}/PKG-INFO +1 -1
  9. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/LICENSE +0 -0
  10. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/MANIFEST.in +0 -0
  11. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/README.md +0 -0
  12. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/setup.cfg +0 -0
  13. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/PgIPInfo.py +0 -0
  14. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/PgView.py +0 -0
  15. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/__init__.py +0 -0
  16. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fill_awsusage.py +0 -0
  17. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fill_cdgusage.py +0 -0
  18. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fill_codusage.py +0 -0
  19. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fill_country.py +0 -0
  20. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fill_endtime.py +0 -0
  21. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fill_globususage.py +0 -0
  22. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fill_ipinfo.py +0 -0
  23. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fill_oneorder.py +0 -0
  24. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fill_osdfusage.py +0 -0
  25. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fill_rdadb.py +0 -0
  26. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fill_tdsusage.py +0 -0
  27. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillawsusage.py +0 -0
  28. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillawsusage.usg +0 -0
  29. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillcdgusage.py +0 -0
  30. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillcdgusage.usg +0 -0
  31. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillcountry.py +0 -0
  32. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillendtime.py +0 -0
  33. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillgdexusage.py +0 -0
  34. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillgdexusage.usg +0 -0
  35. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillglobususage.usg +0 -0
  36. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillipinfo.py +0 -0
  37. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillipinfo.usg +0 -0
  38. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/filloneorder.py +0 -0
  39. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/filloneorder.usg +0 -0
  40. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillosdfusage.py +0 -0
  41. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillosdfusage.usg +0 -0
  42. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/filltdsusage.py +0 -0
  43. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/filltdsusage.usg +0 -0
  44. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillzenodousage.py +0 -0
  45. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/fillzenodousage.usg +0 -0
  46. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/log_arch.py +0 -0
  47. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/logarch.py +0 -0
  48. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/logarch.usg +0 -0
  49. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/pg_ipinfo.py +0 -0
  50. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/pg_view.py +0 -0
  51. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/pgsyspath.py +0 -0
  52. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/view_allusage.py +0 -0
  53. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/view_awsusage.py +0 -0
  54. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/view_checkusage.py +0 -0
  55. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/view_codusage.py +0 -0
  56. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/view_ordusage.py +0 -0
  57. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/view_osdfusage.py +0 -0
  58. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/view_rqstusage.py +0 -0
  59. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/view_tdsusage.py +0 -0
  60. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/view_webfile.py +0 -0
  61. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/view_webusage.py +0 -0
  62. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewallusage.py +0 -0
  63. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewallusage.usg +0 -0
  64. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewawsusage.py +0 -0
  65. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewawsusage.usg +0 -0
  66. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewcheckusage.py +0 -0
  67. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewcheckusage.usg +0 -0
  68. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewcodusage.py +0 -0
  69. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewcodusage.usg +0 -0
  70. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewordusage.py +0 -0
  71. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewordusage.usg +0 -0
  72. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewosdfusage.py +0 -0
  73. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewosdfusage.usg +0 -0
  74. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewrqstusage.py +0 -0
  75. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewrqstusage.usg +0 -0
  76. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewtdsusage.py +0 -0
  77. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewtdsusage.usg +0 -0
  78. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewwebfile.py +0 -0
  79. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewwebfile.usg +0 -0
  80. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewwebusage.py +0 -0
  81. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics/viewwebusage.usg +0 -0
  82. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics.egg-info/SOURCES.txt +0 -0
  83. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics.egg-info/dependency_links.txt +0 -0
  84. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics.egg-info/entry_points.txt +0 -0
  85. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics.egg-info/requires.txt +0 -0
  86. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/src/rda_python_metrics.egg-info/top_level.txt +0 -0
  87. {rda_python_metrics-3.0.9 → rda_python_metrics-3.0.10}/tests/test_metrics.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_metrics
3
- Version: 3.0.9
3
+ Version: 3.0.10
4
4
  Summary: RDA Python Package to gather and view data usage metrics
5
5
  Author-email: Zaihua Ji <zji@ucar.edu>
6
6
  Project-URL: Homepage, https://github.com/NCAR/rda-python-metrics
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "rda_python_metrics"
9
- version = "3.0.9"
9
+ version = "3.0.10"
10
10
  authors = [
11
11
  { name="Zaihua Ji", email="zji@ucar.edu" },
12
12
  ]
@@ -28,14 +28,18 @@ class FillCODUsage(PgIPInfo):
28
28
  self.NDAYS = 0x08 # get COD data usages in recent number of days
29
29
  self.FILES = 0x10 # get given file names
30
30
  self.GTALL = 0x20 # get all data files of read
31
- self.MASKS = (self.MONTH|self.YEARS|self.NDAYS|self.FILES)
31
+ self.DATES = 0x40 # get COD data usages for given dates
32
+ self.PERID = 0x80 # get COD data usages between two dates
33
+ self.MASKS = (self.MONTH|self.YEARS|self.NDAYS|self.FILES|self.DATES|self.PERID)
32
34
  self.USAGE = {
33
35
  'OPTION' : 0,
34
36
  'PGTBL' : "codusage",
35
37
  'WEBLOG' : "/var/log/httpd",
36
38
  }
37
39
  self.USERS = {} # cache user info for aid
38
- self.datelimit = ''
40
+ self.datelimit = '' # earliest log entry date to keep
41
+ self.endlimit = '' # latest log entry date to keep
42
+ self.filldates = None # the exact log entry dates to keep, for -d
39
43
  self.params = [] # array of input values
40
44
 
41
45
  def read_parameters(self):
@@ -44,14 +48,18 @@ class FillCODUsage(PgIPInfo):
44
48
  for arg in argv:
45
49
  if arg == "-b":
46
50
  self.PGLOG['BCKGRND'] = 1
47
- elif re.match(r'^-[afmNy]$', arg) and self.USAGE['OPTION'] == 0:
51
+ elif re.match(r'^-[adfmNpy]$', arg) and self.USAGE['OPTION'] == 0:
48
52
  if arg == "-a":
49
53
  self.USAGE['OPTION'] = self.GTALL
50
54
  self.params = ['']
55
+ elif arg == "-d":
56
+ self.USAGE['OPTION'] = self.DATES
51
57
  elif arg == "-f":
52
58
  self.USAGE['OPTION'] = self.FILES
53
59
  elif arg == "-m":
54
60
  self.USAGE['OPTION'] = self.MONTH
61
+ elif arg == "-p":
62
+ self.USAGE['OPTION'] = self.PERID
55
63
  elif arg == "-y":
56
64
  self.USAGE['OPTION'] = self.YEARS
57
65
  elif arg == "-N":
@@ -69,17 +77,40 @@ class FillCODUsage(PgIPInfo):
69
77
  def start_actions(self):
70
78
  """Function to start actions."""
71
79
  if self.USAGE['OPTION']&self.NDAYS:
72
- curdate = self.curdate()
73
- self.datelimit = self.adddate(curdate, 0, 0, -int(self.params[0]))
74
- self.USAGE['OPTION'] = self.MONTH
75
- self.params = []
76
- while curdate >= self.datelimit:
77
- (year, month, day) = curdate.split('-')
78
- self.params.append("{}-{}".format(year, month))
79
- curdate = self.adddate(curdate, 0, 0, -int(day))
80
+ self.datelimit = self.adddate(self.curdate(), 0, 0, -int(self.params[0]))
81
+ self.set_month_params(self.datelimit, self.curdate())
82
+ elif self.USAGE['OPTION']&self.DATES:
83
+ dates = sorted(self.format_date(dt) for dt in self.params)
84
+ self.filldates = set(dates)
85
+ self.set_month_params(dates[0], dates[-1])
86
+ elif self.USAGE['OPTION']&self.PERID:
87
+ self.datelimit = self.format_date(self.params[0])
88
+ self.endlimit = self.format_date(self.params[1]) if len(self.params) > 1 else self.curdate()
89
+ self.set_month_params(self.datelimit, self.endlimit)
80
90
  self.fill_cod_usages(self.USAGE['OPTION'], self.params)
81
91
  self.pglog(None, self.LOGWRN|self.SNDEML) # send email out if any
82
92
 
93
+ def set_month_params(self, bdate, edate):
94
+ """Replace the inputs with the months holding bdate through edate.
95
+
96
+ One COD log file holds a whole month, so a request made in dates is served
97
+ by reading those months and narrowing the entries in skip_log_date().
98
+ """
99
+ self.USAGE['OPTION'] = self.MONTH
100
+ self.params = []
101
+ curdate = edate
102
+ while curdate >= bdate:
103
+ (year, month, day) = curdate.split('-')
104
+ self.params.append("{}-{}".format(year, month))
105
+ curdate = self.adddate(curdate, 0, 0, -int(day))
106
+
107
+ def skip_log_date(self, cdate):
108
+ """Tell whether a log entry date falls outside what was asked for."""
109
+ if self.filldates is not None: return cdate not in self.filldates
110
+ if self.datelimit and cdate < self.datelimit: return True
111
+ if self.endlimit and cdate > self.endlimit: return True
112
+ return False
113
+
83
114
  def fill_cod_usages(self, option, inputs):
84
115
  """Fill COD usages into table dssdb.codusage of DSS PostgreSQL database from cod access logs."""
85
116
  cntall = cntadd = 0
@@ -128,7 +159,7 @@ class FillCODUsage(PgIPInfo):
128
159
  cntadd += self.add_usage_records(records, cdate)
129
160
  records = {}
130
161
  pdate = cdate
131
- if self.datelimit and cdate < self.datelimit: continue
162
+ if self.skip_log_date(cdate): continue
132
163
  if aid in records:
133
164
  records[aid]['size'] += size
134
165
  records[aid]['count'] += 1
@@ -5,13 +5,18 @@
5
5
  into the 'codusage' table in PostgreSQL database 'rdadb'.
6
6
 
7
7
  USAGE:
8
- fillcodusage [-b] (-a | -f LogFileNames | -m MonthList |
9
- -N NumberDays | -y YearList)
8
+ fillcodusage [-b] (-a | -d LogEntryDates | -f LogFileNames | -m MonthList |
9
+ -N NumberDays | -p BeginDate [EndDate] | -y YearList)
10
10
 
11
- OPTIONS (choose exactly one of -a, -f, -m, -N, or -y):
11
+ OPTIONS (choose exactly one of -a, -d, -f, -m, -N, -p, or -y):
12
12
 
13
13
  -a Process all available log files.
14
14
 
15
+ -d LogEntryDates
16
+ Process the given dates. Date format: YYYY-MM-DD (e.g. 2024-01-15).
17
+ A log file holds a whole month, so the months holding these dates are
18
+ read and only entries falling on the given dates are recorded.
19
+
15
20
  -f LogFileNames
16
21
  Process the given log file names directly.
17
22
 
@@ -22,6 +27,11 @@
22
27
  -N NumberDays
23
28
  Process log files covering the most recent NumberDays days.
24
29
 
30
+ -p BeginDate [EndDate]
31
+ Process log entries between BeginDate and EndDate, inclusive.
32
+ EndDate defaults to today if omitted. As with -d, whole months are
33
+ read and the entries outside the range are skipped.
34
+
25
35
  -y YearList
26
36
  Process log files for the given years.
27
37
  Year format: YYYY (e.g. 2024).
@@ -30,3 +40,4 @@
30
40
 
31
41
  EXAMPLE:
32
42
  fillcodusage -m 2024-01 2024-02
43
+ fillcodusage -d 2024-01-15 2024-02-03
@@ -28,9 +28,11 @@ class FillGlobusUsage(PgIPInfo, PgSplit, PgFile):
28
28
  'PGTBL' : "wusage",
29
29
  'GBSDIR' : self.PGLOG["GDEXWORK"] + "/logs/gridftp/",
30
30
  'GBSLOG' : "access_log_gridftp0{}_{}",
31
+ 'GBSDAYS' : 7, # a log file is named for its first date and holds a week
31
32
  }
32
33
  self.logfiles = []
33
34
  self.datelimits = [None, None]
35
+ self.filldates = None # the exact log entry dates to keep, for -d
34
36
  self.params = [] # array of input values
35
37
  self.option = self.cmdstr = None
36
38
 
@@ -73,11 +75,12 @@ class FillGlobusUsage(PgIPInfo, PgSplit, PgFile):
73
75
  if self.option == 'f':
74
76
  self.logfiles = self.params
75
77
  elif self.option == 'd':
76
- for pdate in self.params:
77
- fdate = self.format_date(pdate, 'MMDDYYYY')
78
- fname = self.USAGE['GBSLOG'].format('?', fdate)
79
- fnames = glob.glob(fname)
80
- if fnames: self.logfiles.extend(sorted(fnames))
78
+ # a log file is named for its first date and holds a week, so the file
79
+ # covering a date is found by looking back, not by its own name
80
+ self.filldates = {self.format_date(pdate) for pdate in self.params}
81
+ for pdate in sorted(self.filldates):
82
+ for fname in self.get_covering_logfiles(pdate):
83
+ if fname not in self.logfiles: self.logfiles.append(fname)
81
84
  else:
82
85
  if self.option == 'N':
83
86
  edate = self.curdate()
@@ -88,13 +91,33 @@ class FillGlobusUsage(PgIPInfo, PgSplit, PgFile):
88
91
  edate = self.datelimits[1] = self.params[1]
89
92
  else:
90
93
  edate = self.curdate()
91
- while pdate <= edate:
92
- fdate = self.format_date(pdate, 'MMDDYYYY')
94
+ # start a week early so the file covering the first dates is picked up;
95
+ # its entries before datelimits[0] are skipped as they are read
96
+ gdate = self.adddate(pdate, 0, 0, -self.USAGE['GBSDAYS'])
97
+ while gdate <= edate:
98
+ fdate = self.format_date(gdate, 'MMDDYYYY')
93
99
  fname = self.USAGE['GBSLOG'].format('?', fdate)
94
- fnames = glob.glob(fname)
95
- if fnames: self.logfiles.extend(sorted(fnames))
96
- pdate = self.adddate(pdate, 0, 0, 1)
100
+ for gname in sorted(glob.glob(fname)):
101
+ if gname not in self.logfiles: self.logfiles.append(gname)
102
+ gdate = self.adddate(gdate, 0, 0, 1)
97
103
 
104
+ def get_covering_logfiles(self, pdate):
105
+ """Get the log files holding pdate, searching back over a week of names."""
106
+ gdate = pdate
107
+ for i in range(self.USAGE['GBSDAYS']):
108
+ fname = self.USAGE['GBSLOG'].format('?', self.format_date(gdate, 'MMDDYYYY'))
109
+ fnames = sorted(glob.glob(fname))
110
+ if fnames: return fnames
111
+ gdate = self.adddate(gdate, 0, 0, -1)
112
+ return []
113
+
114
+ def skip_log_date(self, date):
115
+ """Tell whether a log entry date falls outside what was asked for."""
116
+ if self.filldates is not None: return date not in self.filldates
117
+ if self.datelimits[0] and date < self.datelimits[0]: return True
118
+ if self.datelimits[1] and date > self.datelimits[1]: return True
119
+ return False
120
+
98
121
  def fill_globus_usages(self):
99
122
  """Fill Globus usages into table dssdb.globususage of DSS PostgreSQL database from globus access logs."""
100
123
  cntall = addall = 0
@@ -130,8 +153,7 @@ class FillGlobusUsage(PgIPInfo, PgSplit, PgFile):
130
153
  sline = ms.group(7)
131
154
  engine = ms.group(8)
132
155
  (year, quarter, date, time) = self.get_record_date_time(ms.group(2))
133
- if self.datelimits[0] and date < self.datelimits[0]: continue
134
- if self.datelimits[1] and date > self.datelimits[1]: continue
156
+ if self.skip_log_date(date): continue
135
157
  locflag = 'O' if re.match(r'^https://stratus\.', sline) else 'G'
136
158
  idx = wfile.find('?')
137
159
  if idx > -1: wfile = wfile[:idx]
@@ -32,15 +32,26 @@ class FillRDADB(PgUtil, PgDBI):
32
32
  'OPTION' : 0,
33
33
  'OPTVAL' : '',
34
34
  'DOMAIL' : 1,
35
- 'BCKGRND' : ''
35
+ 'BCKGRND' : '',
36
+ 'BACKDAYS' : 0 # days to reach back for missed dates, set by -B
37
+ }
38
+ # the usage table and its date field, per command to reprocess with -d
39
+ self.BACKFILL = {
40
+ 'fillosdfusage' : ('osdfusage', 'date'),
41
+ 'fillawsusage' : ('awsusage', 'date'),
42
+ 'fillglobususage' : ('wusage', 'date_read'),
43
+ 'fillcodusage' : ('codusage', 'date')
36
44
  }
37
45
  self.params = [] # array of input values
38
46
 
39
47
  def read_parameters(self):
40
48
  """Function to read parameters."""
41
49
  argv = sys.argv[1:]
50
+ backopt = 0 # the value after -B is the number of days to reach back
42
51
  for arg in argv:
43
- if arg == "-b":
52
+ if arg == "-B":
53
+ backopt = 1
54
+ elif arg == "-b":
44
55
  self.PGLOG['BCKGRND'] = "-b"
45
56
  self.RDADB['BCKGRND'] = " -b"
46
57
  elif arg == "-n":
@@ -60,12 +71,20 @@ class FillRDADB(PgUtil, PgDBI):
60
71
  self.RDADB['OPTION'] |= self.NDAYS
61
72
  elif re.match(r'^-.*', arg):
62
73
  self.pglog(arg + ": Invalid Option", self.LGWNEX)
74
+ elif backopt:
75
+ if not re.match(r'^\d+$', arg):
76
+ self.pglog(arg + ": Number of days back must be a whole number", self.LGWNEX)
77
+ self.RDADB['BACKDAYS'] = int(arg)
78
+ backopt = 0
63
79
  elif self.RDADB['OPTION']&self.MASKS:
64
80
  self.params.append(arg)
65
81
  else:
66
82
  self.pglog(arg + ": Invalid Parameter", self.LGWNEX)
83
+ if backopt: self.pglog("-B: Miss number of days to reach back", self.LGWNEX)
67
84
  if not self.RDADB['OPTION'] or (self.RDADB['OPTION']&self.MASKS and not self.params):
68
85
  self.show_usage('fillrdadb')
86
+ if self.RDADB['BACKDAYS'] and not self.RDADB['OPTION']&self.NDAYS:
87
+ self.pglog("-B: Ignored, reaching back for missed dates needs -N", self.LOGWRN)
69
88
  self.cmdlog("fillrdadb {}".format(' '.join(argv)))
70
89
 
71
90
  def start_actions(self):
@@ -88,9 +107,63 @@ class FillRDADB(PgUtil, PgDBI):
88
107
  self.pgsystem("fillawsusage {} {}".format(self.RDADB['BCKGRND'], filecond), self.LGWNEM, 5)
89
108
  # fill available OSDF web data usages
90
109
  self.pgsystem("fillosdfusage {} {}".format(self.RDADB['BCKGRND'], filecond), self.LGWNEM, 5)
110
+ # the -N window is the only thing that reaches a log file again, so one
111
+ # published after its date leaves the window is never asked for; -B catches those
112
+ if self.RDADB['BACKDAYS'] and self.RDADB['OPTION']&self.NDAYS:
113
+ self.backfill_missed_dates(int(self.params[0]))
91
114
  if self.RDADB['DOMAIL']: self.send_email_notice()
92
115
  self.pglog("End Filling RDADB info at {}".format(self.current_datetime()), self.LGWNEM)
93
116
 
117
+ def backfill_missed_dates(self, ndays):
118
+ """Reprocess the dates before the -N window that still hold no usage record.
119
+
120
+ Only runs when -B gave a number of days to reach back. A log file is
121
+ sometimes published after its date has slid out of the -N window, and
122
+ nothing fetches it again, so the date stays empty however often the job
123
+ runs. Asking each usage table which dates it is missing keeps those dates
124
+ being retried until their log shows up, as far back as -B allows.
125
+
126
+ A date whose log holds no usable entry simply keeps being offered until it
127
+ ages out past BACKDAYS. That is deliberate: the obvious alternative, taking
128
+ an already processed log as proof of coverage, would silently write off the
129
+ dates left empty by a run that died partway.
130
+ """
131
+ edate = self.adddate(self.curdate(), 0, 0, -ndays)
132
+ bdate = self.adddate(self.curdate(), 0, 0, -self.RDADB['BACKDAYS'])
133
+ if bdate >= edate: return
134
+ for cmd in self.BACKFILL:
135
+ (tbname, datefld) = self.BACKFILL[cmd]
136
+ dates = self.get_unfilled_dates(tbname, datefld, bdate, edate)
137
+ if not dates: continue
138
+ self.pglog("{}: {} date(s) between {} and {} hold no usage, reprocessing".format(
139
+ cmd, len(dates), bdate, edate), self.LOGWRN)
140
+ self.pgsystem("{} {} -d {}".format(cmd, self.RDADB['BCKGRND'], ' '.join(dates)), self.LGWNEM, 5)
141
+
142
+ def get_unfilled_dates(self, tbname, datefld, bdate, edate):
143
+ """Get the dates in [bdate, edate) holding no record in a usage table."""
144
+ filled = set()
145
+ for table in self.get_usage_tables(tbname, bdate, edate):
146
+ cnd = "{} >= '{}' AND {} < '{}'".format(datefld, bdate, datefld, edate)
147
+ pgrecs = self.pgmget(table, 'DISTINCT ' + datefld, cnd, self.LOGWRN)
148
+ if pgrecs and datefld in pgrecs:
149
+ filled.update(str(d) for d in pgrecs[datefld])
150
+ dates = []
151
+ pdate = bdate
152
+ while pdate < edate:
153
+ if pdate not in filled: dates.append(pdate)
154
+ pdate = self.adddate(pdate, 0, 0, 1)
155
+ return dates
156
+
157
+ def get_usage_tables(self, tbname, bdate, edate):
158
+ """Get the existing table names for a usage table, one per year if split."""
159
+ tables = []
160
+ for year in range(int(bdate[0:4]), int(edate[0:4]) + 1):
161
+ table = "{}_{}".format(tbname, year)
162
+ if self.pgget('information_schema.tables', 'table_name',
163
+ "table_name = '{}'".format(table), self.LOGWRN):
164
+ tables.append(table)
165
+ return tables if tables else [tbname]
166
+
94
167
  def clean_unused_files(self):
95
168
  """Clean unused MSS and Web files."""
96
169
  self.pglog("Check and clean deleted Web files that never been used at {}".format(self.current_datetime()), self.LOGWRN)
@@ -6,7 +6,7 @@
6
6
  fillcodusage, fillglobususage, fillawsusage, fillosdfusage.
7
7
 
8
8
  USAGE:
9
- fillrdadb [-b] [-n]
9
+ fillrdadb [-b] [-n] [-B NumberDaysBack]
10
10
  (-c | -d DateList | -m MonthList | -N NumberDays | -y YearList)
11
11
 
12
12
  OPTIONS (choose exactly one of -c, -d, -m, -N, or -y):
@@ -32,5 +32,23 @@
32
32
 
33
33
  -n Do not send email notification when filling is complete.
34
34
 
35
+ -B NumberDaysBack
36
+ After the -N pass, reprocess any date between NumberDaysBack days ago
37
+ and the start of the -N window that still holds no usage record.
38
+
39
+ A log file is sometimes published after its date has slid out of the
40
+ -N window, and nothing reaches for it again, so that date stays empty
41
+ however often the job runs. Each usage table is asked which dates it
42
+ is missing, and only those dates are reprocessed, so a late log is
43
+ picked up however late it arrives.
44
+
45
+ A date whose log holds no usable entry keeps being offered until it
46
+ ages past NumberDaysBack. That is deliberate: treating an already
47
+ processed log as proof of coverage would silently write off the dates
48
+ left empty by a run that died partway.
49
+
50
+ Needs -N, and is ignored with a warning otherwise.
51
+
35
52
  EXAMPLE:
36
53
  fillrdadb -N 7
54
+ fillrdadb -N 14 -B 60 # weekly fill, reaching back two months
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_metrics
3
- Version: 3.0.9
3
+ Version: 3.0.10
4
4
  Summary: RDA Python Package to gather and view data usage metrics
5
5
  Author-email: Zaihua Ji <zji@ucar.edu>
6
6
  Project-URL: Homepage, https://github.com/NCAR/rda-python-metrics