# # # get_dashboard_data_util # # subroutine(get_report_cells_dat( node columns), ( # Returns report_cells JSON string. # Note, values may not yet exist, check for node existence! debug_message("#### get_report_cells_dat() \n"); # debug_message("\n" . node_as_string(columns) . "\n"); string report_cells_dat = "["; node column; string label; string item_value; foreach column columns ( if (@column{"is_report_field"}) then ( label = @column{"label"}; if (label ne "") then ( label = encode_json(label); ); item_value = 0; if (column?{"item_value"}) then ( item_value = @column{"item_value"}; ); report_cells_dat .= "[true,"; report_cells_dat .= "\"" . label . "\","; report_cells_dat .= "\"" . item_value . "\"],"; # report value, becomes loaded after report generation ) else ( report_cells_dat .= "[false],"; # Ignore the cell ); ); report_cells_dat = replace_last(report_cells_dat, ",", "]"); # return report_cells_dat; )); subroutine(get_dashboard_cell_data( node dashboard_column, string profile_name), ( debug_message("#### get_dashboard_cell_data() \n"); node cell_definition; bool show_label = false; string label; string report_field_name; if (?(dashboard_column . ".profiles." . profile_name) and @(dashboard_column . ".profiles." . profile_name . ".report_field") ne "") then ( # Specific cell for the given profile cell_definition = dashboard_column . ".profiles." . profile_name; show_label = @cell_definition{"show_label"}; ) else ( # Report field is defined in column and applies to all # cells/profiles where the report field exists cell_definition = dashboard_column; show_label = @cell_definition{"show_cell_labels"}; ); debug_message("#### cell_definition:\n" . node_as_string(cell_definition) . "\n"); report_field_name = @cell_definition{"report_field"}; debug_message("#### report_field_name: " . report_field_name . "\n"); # Make sure the report_field_exists node profile = "profiles." . profile_name; node report_fields = profile . ".statistics.report_fields"; debug_message("#### report_field exists: " . (report_fields?{report_field_name}) . "\n"); if (report_fields?{report_field_name}) then ( # TODO - The cell labels already exist in client # in profiles_dashboard.cfg JSON data, so we shouldn't # get them again here. # Check if we show a label if (show_label) then ( if (@cell_definition{"label"} ne "") then ( # Show custom label label = @cell_definition{"label"}; ) else ( node report_field_item = report_fields{report_field_name}; # Show report field label if (@report_field_item{"column_label"} ne "") then ( label = @report_field_item{"column_label"}; ) else ( label = @report_field_item{"label"}; ); label = get_expanded_label(label); ); ); ) else ( # Ignore the cell report_field_name = ""; ); # Return node n = new_node(); n{"label"} = label; n{"report_field"} = report_field_name; # debug_message("#### n:\n" . node_as_string(n) . "\n"); n; )); subroutine(get_profile_dashboard_report( node profiles_dashboard, string profile_name, string db_last_modified), ( debug_message("#### get_profile_dashboard_report() \n"); node dashboard_columns = profiles_dashboard{"columns"}; string date_filter = @profiles_dashboard{"date_filter"}; # node profile = "profiles." . profile_name; node dashboard_column; node dashboard_cell; # Create query_header for overview query and response object bool is_valid_dashboard_cell = false; # Row has at least one valid report field # Track the dashboard columns for this profile # for report generation and to get the # report values. delete_node("v._dashboard_cells_info"); v._dashboard_cells_info = ""; node dashboard_cells_info = "v._dashboard_cells_info"; int count = 0; string report_cell_label; string report_cells_dat = "["; foreach dashboard_column dashboard_columns ( dashboard_cell = get_dashboard_cell_data(dashboard_column, profile_name); dashboard_cells_info{count} = ""; if (@dashboard_cell{"report_field"} ne "") then ( is_valid_dashboard_cell = true; report_cell_label = @dashboard_cell{"label"}; dashboard_cells_info{count}{"is_report_field"} = true; dashboard_cells_info{count}{"label"} = report_cell_label; dashboard_cells_info{count}{"report_field"} = @dashboard_cell{"report_field"}; ) else ( dashboard_cells_info{count}{"is_report_field"} = false; ); count++; ); # debug_message("\n" . node_as_string(dashboard_cells_info) . "\n"); delete_node("v._dashboard_report"); v._dashboard_report = ""; node dashboard_report = "v._dashboard_report"; dashboard_report{"is_valid_dashboard_cell"} = is_valid_dashboard_cell; if (is_valid_dashboard_cell) then ( # Create node # TODO, Check if we need to add the profiles filter expression. # Get profile file modification_time to be included in the report checksum. string profile_path = LOGANALYSISINFO_DIRECTORY . "profiles/" . profile_name . ".cfg"; node profile_file_info = new_node(); get_file_info(profile_path, profile_file_info); debug_message("##### profile_file_info:\n" . node_as_string(profile_file_info) . "\n"); string profile_last_modified = @profile_file_info{"modification_time"}; string report_checksum = md5_digest( profile_last_modified . db_last_modified . date_filter . node_as_string(dashboard_cells_info)); dashboard_report{"report_checksum"} = report_checksum; dashboard_report{"db_last_modified"} = db_last_modified; dashboard_report{"date_filter"} = date_filter; clone_node(dashboard_cells_info, dashboard_report . ".columns"); ); # Return dashboard_report; )); # # # manage_profiles_dashboard_report_generation() # # subroutine(manage_profiles_dashboard_report_generation( string session_id, string page_token, string active_page, node session_profiles_dashboard_profiles), ( # This handles the simultaneous generation of profiles dashboard reports debug_message("#### manage_profiles_dashboard_report_generation() \n"); string session_profiles_dashboard_dir = LOGANALYSISINFO_DIRECTORY . "sessions_cache/" . session_id . "/profiles_dashboard"; # Track the profiles which for which no report is yet generated # and count the number of active threads. int max_simultaneous_threads = 10; int num_active_threads = 0; node item; string profile_name; string report_checksum; bool report_generation_started = false; # Keep track of profiles for which we need yet to generate a report. node profiles_queue = new_node(); string cached_report_txt_file_path; foreach item session_profiles_dashboard_profiles ( profile_name = @item{"profile_name"}; report_checksum = @item{"report_checksum"}; # debug_message("\n#### profile_name: " . profile_name . "\n"); # debug_message("#### report_checksum: " . report_checksum . "\n"); # Only check for report generation if report does not exist in profiles cache cached_report_txt_file_path = LOGANALYSISINFO_DIRECTORY . "profiles_cache/" . profile_name; cached_report_txt_file_path .= "/profiles_dashboard/" . report_checksum . ".txt"; # debug_message("#### cached_report_txt_file_path: " . cached_report_txt_file_path . "\n"); if (!file_exists(cached_report_txt_file_path)) then ( # debug_message("#### NO REPORT TXT FILE IN PROFILES CACHE \n"); report_generation_started = file_exists(session_profiles_dashboard_dir . "/report_generation_started/" . report_checksum . ".txt"); if (!report_generation_started) then ( # Add profile to profiles_queue profiles_queue{profile_name} = report_checksum; ) else ( # Report generation thread must be active num_active_threads++; ); ); # else ( # # debug_message("#### CACHED TXT FILE EXISTS IN PROFILES CACHE \n"); # ); # # debug_message(" ------------------------ \n"); ); # # # Start generating profile reports in profiles_queue # # debug_message("#### num_active_threads: " . num_active_threads . "\n"); int num_free_threads = max_simultaneous_threads - num_active_threads; int count = 0; debug_message("#### num_free_threads: " . num_free_threads . "\n"); # debug_message("#### profiles_queue: " . node_as_string(profiles_queue) . "\n"); foreach item profiles_queue ( if (count < num_free_threads) then ( profile_name = node_name(item); report_checksum = @item; # Start new thread for report generation volatile.options.1 = "background"; volatile.options.2 = "-dp"; volatile.options.3 = "templates.admin_pages.profiles_dashboard.create_dashboard_report"; volatile.options.4 = "-v"; volatile.options.5 = "e"; volatile.options.6 = "p"; volatile.options.7 = profile_name; volatile.options.8 = "volatile.session_id"; volatile.options.9 = session_id; volatile.options.10 = "v.fp.page_token"; volatile.options.11 = page_token; volatile.options.12 = "v.fp.active_page"; volatile.options.13 = "profiles"; volatile.options.14 = "v.fp.report_checksum"; volatile.options.15 = report_checksum; string task_id = exec("", "volatile.options", false); session_profiles_dashboard_profiles{profile_name}{"task_id"} = task_id; # Create a text file in report_generation_started so that we know that # report generation started. We use the text file approach to avoid race conditions. string file_path = session_profiles_dashboard_dir . "/report_generation_started/" . report_checksum . ".txt"; write_file(file_path, "profile: " . profile_name); count++; ) else ( last; ); ); save_node(session_profiles_dashboard_profiles); ));