1818import logging
1919from datetime import datetime
2020import requests
21- from shared .helpers .database import Database
2221from shared .helpers .timezone import (
2322 extract_timezone_from_json_validation_report ,
2423 get_service_date_range_with_timezone_utc ,
2524)
2625import functions_framework
26+ from shared .helpers .database import Database
2727from shared .database_gen .sqlacodegen_models import (
2828 Validationreport ,
2929 Feature ,
@@ -164,6 +164,10 @@ def generate_report_entities(
164164 feature = get_feature (feature_name , session )
165165 feature .validations .append (validation_report_entity )
166166 entities .append (feature )
167+
168+ # Process notices and compute counters
169+ counters = process_validation_report_notices (json_report ["notices" ])
170+
167171 for notice in json_report ["notices" ]:
168172 notice_entity = Notice (
169173 dataset_id = dataset .id ,
@@ -174,6 +178,14 @@ def generate_report_entities(
174178 )
175179 dataset .notices .append (notice_entity )
176180 entities .append (notice_entity )
181+
182+ # Update the validation report entity with computed counters
183+ validation_report_entity .total_info = counters ["total_info" ]
184+ validation_report_entity .total_warning = counters ["total_warning" ]
185+ validation_report_entity .total_error = counters ["total_error" ]
186+ validation_report_entity .unique_info_count = counters ["unique_info_count" ]
187+ validation_report_entity .unique_warning_count = counters ["unique_warning_count" ]
188+ validation_report_entity .unique_error_count = counters ["unique_error_count" ]
177189 return entities
178190
179191
@@ -227,7 +239,6 @@ def create_validation_report_entities(feed_stable_id, dataset_stable_id, version
227239 try :
228240 with db .start_db_session () as session :
229241 logging .info ("Database session started." )
230-
231242 # Generate the database entities required for the report
232243 try :
233244 entities = generate_report_entities (
@@ -301,3 +312,88 @@ def process_validation_report(request):
301312 f"Processing validation report version { validator_version } for dataset { dataset_id } in feed { feed_id } ."
302313 )
303314 return create_validation_report_entities (feed_id , dataset_id , validator_version )
315+
316+
317+ @functions_framework .http
318+ def compute_validation_report_counters (request ):
319+ """
320+ Compute the total number of errors, warnings, and info notices,
321+ as well as the number of distinct codes for each severity level
322+ across all validation reports in the database, and write the results to the database.
323+ """
324+ batch_size = 100 # Number of reports to process in each batch
325+ offset = 0
326+ db = Database ()
327+ with db .start_db_session (echo = False ) as session :
328+ while True :
329+ validation_reports = (
330+ session .query (Validationreport ).limit (batch_size ).offset (offset ).all ()
331+ )
332+ print (
333+ f"Processing { len (validation_reports )} validation reports from offset { offset } ."
334+ )
335+ # Break the loop if no more reports are found
336+ if len (validation_reports ) == 0 :
337+ break
338+
339+ for report in validation_reports :
340+ counters = process_validation_report_notices (report .notices )
341+
342+ # Update the report with computed counters
343+ report .total_info = counters ["total_info" ]
344+ report .total_warning = counters ["total_warning" ]
345+ report .total_error = counters ["total_error" ]
346+ report .unique_info_count = counters ["unique_info_count" ]
347+ report .unique_warning_count = counters ["unique_warning_count" ]
348+ report .unique_error_count = counters ["unique_error_count" ]
349+
350+ logging .info (
351+ f"Updated ValidationReport { report .id } with counters: "
352+ f"INFO={ report .total_info } , WARNING={ report .total_warning } , ERROR={ report .total_error } , "
353+ f"Unique INFO Code={ report .unique_info_count } , Unique WARNING Code={ report .unique_warning_count } , "
354+ f"Unique ERROR Code={ report .unique_error_count } "
355+ )
356+
357+ # Commit the changes for the current batch
358+ session .commit ()
359+
360+ # Move to the next batch
361+ offset += batch_size
362+
363+ return {"message" : "Validation report counters computed successfully." }, 200
364+
365+
366+ def process_validation_report_notices (notices ):
367+ """
368+ Processes the notices of a validation report and computes counters for different severities.
369+
370+ :param report: A Validationreport object containing associated notices.
371+ :return: A dictionary with computed counters for total and unique counts of INFO, WARNING, and ERROR severities.
372+ """
373+ # Initialize counters for the current report
374+ total_info , total_warning , total_error = 0 , 0 , 0
375+ info_codes , warning_codes , error_codes = set (), set (), set ()
376+
377+ # Process associated notices
378+ for notice in notices :
379+ match notice .severity :
380+ case "INFO" :
381+ total_info += notice .total_notices
382+ info_codes .add (notice .notice_code )
383+ case "WARNING" :
384+ total_warning += notice .total_notices
385+ warning_codes .add (notice .notice_code )
386+ case "ERROR" :
387+ total_error += notice .total_notices
388+ error_codes .add (notice .notice_code )
389+ case _:
390+ logging .warning (f"Unknown severity: { notice .severity } " )
391+
392+ return {
393+ "total_info" : total_info ,
394+ "total_warning" : total_warning ,
395+ "total_error" : total_error ,
396+ "unique_info_count" : len (info_codes ),
397+ "unique_warning_count" : len (warning_codes ),
398+ "unique_error_count" : len (error_codes ),
399+ }
0 commit comments