# # This contains code for managing snapons (adding and removing them from a profile) # include "lib.database"; include "lib.profile"; # # get_unique_node_name() # # Purpose: This gets a unique name of the form N where is specified and N is chosen to be the lowest # integer > 1, that gives a node name not found in the specified now. # # Parameters: n: the node to look in # name: the desired name of the node # returns name if it does not exist in n, or nameN where N is an integer and nameN does not exist in n # subroutine(get_unique_node_name(node n, string name), ( # If there is no node using the desired name, just use that name. if (!n?{name}) then name; # Otherwise, count up until we find an unused node with the name we wanted, plus an integer else ( int num = 2; while (n?{name . '_' . num}) num++; name . '_' . num; ); # if name used )); #### get_unique_node_name() #### # # set_node_with_default() # # Purpose: This copies a particular subnode value from the snapon node to the final node, using a default if it doesn't exist # # Parameters: snapon: the snapon instance # profile_node: the node in the profile # snapon_node: the node in the snapon # name: the subnode name # value: the default value, or "" if the subnode must exist in snapon_node # # formerly set_node_with_default subroutine(set_node_with_default(node snapon, node profile_node, node snapon_node, string name, string value), ( if (snapon_node?{name}) then ( # if (starts_with(@report_element{name}, "variable:")) then ( # string resolved_variable = resolve_variable(snapon, @report_element{name}); # @profile_report_element{name} = resolved_variable; ## error("variable detected: " . @report_element{name}); # ); # else ( @profile_node{name} = @snapon_node{name}; # ); ); else ( if (value eq "") then error("Snapon: Required report element parameter " . name . " not specified in snapon"); else @profile_node{name} = value; ); )); #### set_node_with_default() #### # # add_in_snapon() # # Purpose: This determines whether to add this element in a snapon, by looking at the add_in_snapon subnode # subroutine(add_in_snapon(node n), ( (!(n?{'add_in_snapon'}) or @n{'add_in_snapon'}); )); # add_in_snapon() # # resolve_variables() # # Purpose: This resolves any variables/parameters in the node we're attaching # # Parameters: n: the node to resolve variables in # parameters: the parameters node # subroutine(resolve_variables(node n, node parameters), ( # echo("Resolving: " . node_as_string(n)); # Evaluate (expand) all Salang section in the node name while (matches_regular_expression(node_name(n), "^(.*)[{]=(.*)$")) ( string prefix = $1; string suffix = $2; if (matches_regular_expression(suffix, "^(.*)=[}](.*)$")) then ( suffix = $2; string expression = $1; node compiled_expression = compile(expression); string evaluated_expression = evaluate(compiled_expression); #echo("Resolved (node name): " . expression . " -> " . evaluated_expression); if (evaluated_expression eq "") then error("Empty value for resolved snapon expression '" . expression . "'; node name expressions cannot resolve to empty"); rename_node(n, prefix . evaluated_expression . suffix); ); else ( error("No closing =} in snapon expression: " . @n); ); ); # while node name contains Salang # Evaluate (expand) all Salang section in the node value while (matches_regular_expression(@n, "^(.*)[{]=(.*)$")) ( string prefix = $1; string suffix = $2; if (matches_regular_expression(suffix, "^(.*)=[}](.*)$")) then ( suffix = $2; string expression = $1; #echo("prefix=" . prefix); #echo("suffix=" . suffix); #echo("expression=" . expression); node compiled_expression = compile(expression); string evaluated_expression = evaluate(compiled_expression); #echo("Resolved: " . expression . " -> " . evaluated_expression); # if (evaluated_expression eq "") then # echo("Warning: Empty value for resolved expression '" . expression . "'"); @n = prefix . evaluated_expression . suffix; ); else ( error("No closing =} in snapon expression: " . @n); ); ); # while node value contains Salang # Recursively evaluate the subnodes node subn; foreach subn n ( resolve_variables(subn, parameters); ); #echo("done resolving"); )); #### resolve_variables() #### # # resolve_escaped_salang_sections() # # Purpose: This resolves any {x= =x} sections into { = = }. # # Parameters: n: the node to resolve variables in # subroutine(resolve_escaped_salang_sections(node n), ( # echo("Resolving escaped Salang: " . node_as_string(n)); # Replace all {x= with { =, an all =x} with = } if (contains(@n, "{x=")) then ( @n = replace_all(@n, "{x=", "{="); @n = replace_all(@n, "=x}", "=}"); ); # if node value contains {x= # Recursively evaluate the subnodes node subn; foreach subn n ( resolve_escaped_salang_sections(subn); ); )); #### resolve_escaped_salang_sections() #### # # snapon_add_database_fields() # # Purpose: This adds a database field to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_database_fields operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_database_fields(node snapon, node profile, node attach_operation, node detach_operations), ( node fields = attach_operation{"fields"}; node field; node profile_database_fields = profile{"database"}{"fields"}; # echo("profile_database_fields BEFORE: " . node_as_string(profile_database_fields)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_database_fields"; # Add all specified database fields foreach field fields ( if (add_in_snapon(field)) then ( # Add the database field node to the profile # echo("field: " . node_as_string(field)); if (profile_database_fields?{node_name(field)}) then error("Snapon attempted to add database field '" . node_name(field) . "', which already exists"); string name = get_unique_node_name(profile_database_fields, node_name(field)); node field_clone = clone_node(field); rename_node(field_clone, name); string label = get_default_field_label(name, "none"); #echo("label: " . label); # Set node defaults set_node_with_default(snapon, field_clone, field_clone, "type", "string"); set_node_with_default(snapon, field_clone, field_clone, "label", label); set_node_with_default(snapon, field_clone, field_clone, "derivation_method", "log_field"); set_node_with_default(snapon, field_clone, field_clone, "category", ""); set_node_with_default(snapon, field_clone, field_clone, "log_field", name); set_node_with_default(snapon, field_clone, field_clone, "aggregation_method", "none"); set_node_with_default(snapon, field_clone, field_clone, "index", false); set_node_with_default(snapon, field_clone, field_clone, "suppress_top", 0); set_node_with_default(snapon, field_clone, field_clone, "suppress_bottom", 2); set_node_with_default(snapon, field_clone, field_clone, "always_include_bottom_level_items", false); set_node_with_default(snapon, field_clone, field_clone, "integer_bits", 0); set_node_with_default(snapon, field_clone, field_clone, "itemnums_hash_function", "rand_sum"); set_node_with_default(snapon, field_clone, field_clone, "sql_field_length", 200); insert_node(profile_database_fields, field_clone, num_subnodes(profile_database_fields)); # echo("Added database field '" . node_name(field) . "'"); bool has_source_dbfield = field?{"source_database_field"}; # Get the database info node database_info = get_database_info(node_name(profile), false); # echo("database info: " . node_as_string(database_info)); #echo("field_clone: " . node_as_string(field_clone)); # Add the database field column to main_table, if it exists, and if it's not sourced from another field if (!has_source_dbfield) then ( if (database_info?{"database_is_ready_for_reporting"}) then ( if (database_table_exists(get_database_table_name(profile, "main_table"))) then ( string sql_field_type = @field_clone{"type"}; if (sql_field_type eq "unique") then sql_field_type = "int"; else if (sql_field_type eq "string") then sql_field_type = "int"; string query = "alter table " . get_database_table_name(profile, "main_table") . " add " . node_name(field) . " " . sql_field_type; # echo(query); database_sql_query(query, true, false); ); ); ); # if !has_source_dbfield @detach_operation{"fields"}{name} = ""; ); # if add field ); # foreach fields # echo("profile_database_fields AFTER: " . node_as_string(profile_database_fields)); # error("add_snapon: add_database_fields unimplemented"); )); #### snapon_add_database_fields() #### # # snapon_remove_database_fields() # # Purpose: This removes a database field from a profile, using a snapon node operation # # Parameters: profile: the profile to remove to # attach_operation: the snapon remove_database_fields operation node # subroutine(snapon_remove_database_fields(node profile, node attach_operation), ( node fields = attach_operation{"fields"}; node field; node profile_database_fields = profile{"database"}{"fields"}; node profile_log_fields = profile{"log"}{"fields"}; # echo("profile_database_fields BEFORE: " . node_as_string(profile_database_fields)); # Remove all specified database fields foreach field fields ( # Remove the database field node to the profile # echo("field: " . node_as_string(field)); node database_field_node = profile_database_fields{node_name(field)}; bool has_source_dbfield = database_field_node?{"source_database_field"}; # echo("database_field_node=" . node_as_string(database_field_node)); #echo("has_source_dbfield: " . has_source_dbfield); delete_node(database_field_node); # echo("Removed database field '" . node_name(field) . "'"); # echo("profile_database_fields=" . profile_database_fields); # save_node(profile); #rewrite_database_config(profile); # If there is a log field for this database field, remove it too if (profile_log_fields?{node_name(field)}) then ( node log_field_node = profile_log_fields{node_name(field)}; delete_node(log_field_node); ); # Remove the database field column from main_table, if it exists, and if it's not sourced from another field if (!has_source_dbfield) then ( if (database_table_exists(get_database_table_name(profile, "main_table"))) then ( string query = "alter table " . get_database_table_name(profile, "main_table") . " drop column " . node_name(field); # echo(query); database_sql_query(query, true, false); ); ); # if !has source dbfield ); # foreach fields # echo("profile_database_fields AFTER: " . node_as_string(profile_database_fields)); )); #### snapon_remove_database_fields() #### # # snapon_add_log_fields() # # Purpose: This adds a log field to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_log_fields operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_log_fields(node snapon, node profile, node attach_operation, node detach_operations), ( node fields = attach_operation{"fields"}; node field; node profile_log_fields = profile{"log"}{"fields"}; # echo("profile_log_fields BEFORE: " . node_as_string(profile_log_fields)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_log_fields"; # Add all specified log fields foreach field fields ( if (add_in_snapon(field)) then ( # Add the log field node to the profile # echo("field: " . node_as_string(field)); if (profile_log_fields?{node_name(field)}) then error("Snapon attempted to add log field '" . node_name(field) . "', which already exists"); string name = get_unique_node_name(profile_log_fields, node_name(field)); node field_clone = clone_node(field); rename_node(field_clone, name); # Set node defaults set_node_with_default(snapon, field_clone, field_clone, "type", "flat"); set_node_with_default(snapon, field_clone, field_clone, "index", 0); set_node_with_default(snapon, field_clone, field_clone, "subindex", 0); set_node_with_default(snapon, field_clone, field_clone, "hierarchy_dividers", ""); set_node_with_default(snapon, field_clone, field_clone, "left_to_right", false); set_node_with_default(snapon, field_clone, field_clone, "leading_divider", false); set_node_with_default(snapon, field_clone, field_clone, "case_sensitive", false); insert_node(profile_log_fields, field_clone, num_subnodes(profile_log_fields)); # echo("Added log field '" . node_name(field) . "'"); @detach_operation{"fields"}{name} = ""; ); # if add field ); # foreach fields # echo("profile_log_fields AFTER: " . node_as_string(profile_log_fields)); # error("add_snapon: add_log_fields unimplemented"); )); #### snapon_add_log_fields() #### # # snapon_remove_log_fields() # # Purpose: This removes a log field from a profile, using a snapon node operation # # Parameters: profile: the profile to remove to # attach_operation: the snapon remove_log_fields operation node # subroutine(snapon_remove_log_fields(node profile, node attach_operation), ( node fields = attach_operation{"fields"}; node field; node profile_log_fields = profile{"log"}{"fields"}; node profile_log_fields = profile{"log"}{"fields"}; # echo("profile_log_fields BEFORE: " . node_as_string(profile_log_fields)); # Remove all specified log fields foreach field fields ( # Remove the log field node to the profile # echo("field: " . node_as_string(field)); node log_field_node = profile_log_fields{node_name(field)}; # echo("log_field_node=" . node_as_string(log_field_node)); delete_node(log_field_node); # echo("Removed log field '" . node_name(field) . "'"); # echo("profile_log_fields=" . profile_log_fields); # save_node(profile); #rewrite_log_config(profile); ); # foreach fields # echo("profile_log_fields AFTER: " . node_as_string(profile_log_fields)); )); #### snapon_remove_log_fields() #### # # snapon_edit_profile_node() # # Purpose: This edits a profile node, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon edit_profile_node operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_edit_profile_node(node snapon, node profile, node attach_operation, node detach_operations), ( string nodepath = @attach_operation{"node"}; string original_value = @profile{nodepath}; string new_value = @attach_operation{"new_value"}; @profile{nodepath} = new_value; # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "unedit_profile_node"; @detach_operation{"nodepath"} = nodepath; @detach_operation{"original_value"} = original_value; )); #### snapon_edit_profile_node() #### # # snapon_unedit_profile_node() # # Purpose: This removes an edit of a profile node, using a snapon node operation # # Parameters: profile: the profile # attach_operation: the snapon unedit_profile_node operation node # subroutine(snapon_unedit_profile_node(node profile, node detach_operations), ( string nodepath = @detach_operations{"nodepath"}; string original_value = @detach_operations{"original_value"}; @profile{nodepath} = original_value; )); #### snapon_unedit_profile_node() #### # # snapon_add_snapons() # # Purpose: This adds a snapon to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_snapon operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(attach_snapon(node profile, node snapon_node, string attached_snapon_name), ()); subroutine(snapon_add_snapons(node profile, node attach_operation, node detach_operations), ( node snapons = attach_operation{"snapons"}; node snapon; node profile_snapons = profile{"snapons"}; # echo("profile_snapons BEFORE: " . node_as_string(profile_snapons)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_snapons"; # Add all specified database snapons node snapon_info; foreach snapon_info snapons ( if (add_in_snapon(snapon_info)) then ( #echo("Got snapon info: " . node_as_string(snapon_info)); # Attach the snapon string snapon_name = @snapon_info{"snapon"}; string snapon_instance_node_name = get_unique_node_name(profile_snapons, @snapon_info{"name"}); #echo("snapon_name: " . snapon_name); #echo("snapon_instance_node_name: " . snapon_instance_node_name); # Get the snapon we're going to attach node snapon = clone_node('snapons'{snapon_name}); # Overlay the information from the plug-in, onto the snapon node overlay_node(snapon, snapon_info); #echo("Attaching snapon [" . snapon_instance_node_name . "]: info=" . node_as_string(snapon_info)); attach_snapon(profile, snapon, snapon_instance_node_name); @detach_operation{"snapons"}{snapon_instance_node_name} = ""; ); # if add_in_snapon ); # foreach snapons # echo("profile_database_snapons AFTER: " . node_as_string(profile_database_snapons)); # error("add_snapon: add_database_snapons unimplemented"); )); #### snapon_add_snapons() #### # # snapon_remove_snapons() # # Purpose: This removes a snapon from a profile, using a snapon node operation # # Parameters: profile: the profile to remove to # attach_operation: the snapon remove_snapons operation node # subroutine(detach_snapon_instance(node profile, string snapon_instance_name), ()); subroutine(snapon_remove_snapons(node profile, node attach_operation), ( node snapons = attach_operation{"snapons"}; node snapon; node profile_snapons = profile{"database"}{"snapons"}; node profile_log_snapons = profile{"log"}{"snapons"}; # echo("profile_snapons BEFORE: " . node_as_string(profile_snapons)); # Remove all specified snapons foreach snapon snapons ( # Remove the database snapon node to the profile string snapon_instance_name = node_name(snapon); #echo("Detaching instance " . snapon_instance_name); detach_snapon_instance(profile, snapon_instance_name); ); # foreach snapons # echo("profile_snapons AFTER: " . node_as_string(profile_snapons)); )); #### snapon_remove_snapons() #### # # snapon_execute_expression() # # Purpose: This executes a Salang expression requested by a snapon # # Parameters: profile: the profile # attach_operation: the snapon add_snapon operation node (which contains the expression) # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_execute_expression(node profile, node attach_operation, node detach_operations), ( # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "execute_expression"; @detach_operation{"expression"} = "# no undo of execute_expression"; # Execute the expression string expression = @attach_operation{"expression"}; #echo("expression: " . expression); node compiled_expression = compile(expression); evaluate(compiled_expression); )); #### snapon_execute_expression() #### # # snapon_add_database_filters() # # Purpose: This adds a database filter to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_database_filters operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_database_filters(node profile, node attach_operation, node detach_operations), ( node filters = attach_operation{"filters"}; node filter; node profile_database_filters = profile{"database"}{"filters"}; # echo("profile_database_filters BEFORE: " . node_as_string(profile_database_filters)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_database_filters"; # Add all specified database filters foreach filter filters ( if (add_in_snapon(filter)) then ( # Add the database filter node to the profile # echo("filter: " . node_as_string(filter)); if (profile_database_filters?{node_name(filter)}) then error("Snapon attempted to add database filter '" . node_name(filter) . "', which already exists"); string filter_node_name = get_unique_node_name(profile_database_filters, node_name(filter)); node cloned_filter = clone_node(filter); rename_node(cloned_filter, filter_node_name); insert_node(profile_database_filters, cloned_filter, num_subnodes(profile_database_filters)); # echo("Added database filter '" . node_name(filter) . "'"); @detach_operation{"filters"}{filter_node_name} = ""; ); # if add_in_snapon ); # foreach filters # echo("profile_database_filters AFTER: " . node_as_string(profile_database_filters)); # error("add_snapon: add_database_filters unimplemented"); )); #### snapon_add_database_filters() #### # # snapon_remove_database_filters() # # Purpose: This removes a database filter from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_database_filters operation node # subroutine(snapon_remove_database_filters(node profile, node attach_operation), ( node filters = attach_operation{"filters"}; node filter; node profile_database_filters = profile{"database"}{"filters"}; # echo("profile_database_filters BEFORE: " . node_as_string(profile_database_filters)); # Remove all specified database filters foreach filter filters ( # Remove the database filter node to the profile # echo("filter: " . node_as_string(filter)); node database_filter_node = profile_database_filters{node_name(filter)}; delete_node(database_filter_node); # echo("Removed database filter '" . node_name(filter) . "'"); ); # foreach filters # echo("profile_database_filters AFTER: " . node_as_string(profile_database_filters)); )); #### snapon_remove_database_filters() #### # # snapon_add_log_filters() # # Purpose: This adds a log filter to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_log_filters operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_log_filters(node profile, node attach_operation, node detach_operations), ( #echo("attach_operation: " . node_as_string(attach_operation)); node filters = attach_operation{"filters"}; node filter; node profile_log_filters = profile{"log"}{"filters"}; # echo("profile_log_filters BEFORE: " . node_as_string(profile_log_filters)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_log_filters"; # Add all specified log filters foreach filter filters ( if (add_in_snapon(filter)) then ( # Add the log filter node to the profile # echo("filter: " . node_as_string(filter)); if (profile_log_filters?{node_name(filter)}) then error("Snapon attempted to add log filter '" . node_name(filter) . "', which already exists"); string filter_node_name = get_unique_node_name(profile_log_filters, node_name(filter)); node cloned_filter = clone_node(filter); rename_node(cloned_filter, filter_node_name); insert_node(profile_log_filters, cloned_filter, num_subnodes(profile_log_filters)); # echo("Added log filter '" . node_name(filter) . "'"); @detach_operation{"filters"}{filter_node_name} = ""; ); # if add_in_snapon ); # foreach filters # echo("profile_log_filters AFTER: " . node_as_string(profile_log_filters)); # error("add_snapon: add_log_filters unimplemented"); )); #### snapon_add_log_filters() #### # # snapon_add_log_filter_initializations() # # Purpose: This adds filter initialization sections to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_log_filter_initializations operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_log_filter_initializations(node profile, node attach_operation, node detach_operations), ( node log_filter_initializations = attach_operation{"log_filter_initializations"}; node profile_log_filter_initialization = profile{"log"}{"filter_initialization"}; # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_log_filter_initializations"; # Add all specified log filter initializations node log_filter_initialization; foreach log_filter_initialization log_filter_initializations ( # Add the log filter_initialization node to the profile string log_filter_initialization_node_name = get_unique_node_name(profile_log_filter_initialization, node_name(log_filter_initialization)); node cloned_log_filter_initialization = clone_node(log_filter_initialization); rename_node(cloned_log_filter_initialization, log_filter_initialization_node_name); insert_node(profile_log_filter_initialization, cloned_log_filter_initialization, num_subnodes(profile_log_filter_initialization)); @detach_operation{"log_filter_initializations"}{log_filter_initialization_node_name} = ""; ); # foreach log_filter_initialization )); #### snapon_add_log_filter_initializations() #### # # snapon_add_log_filter_finalizations() # # Purpose: This adds filter finalization sections to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_log_filter_finalizations operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_log_filter_finalizations(node profile, node attach_operation, node detach_operations), ( node log_filter_finalizations = attach_operation{"log_filter_finalizations"}; node profile_log_filter_finalization = profile{"log"}{"filter_finalization"}; # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_log_filter_finalizations"; # Add all specified log filter finalizations node log_filter_finalization; foreach log_filter_finalization log_filter_finalizations ( # Add the log filter_finalization node to the profile string log_filter_finalization_node_name = get_unique_node_name(profile_log_filter_finalization, node_name(log_filter_finalization)); node cloned_log_filter_finalization = clone_node(log_filter_finalization); rename_node(cloned_log_filter_finalization, log_filter_finalization_node_name); insert_node(profile_log_filter_finalization, cloned_log_filter_finalization, num_subnodes(profile_log_filter_finalization)); @detach_operation{"log_filter_finalizations"}{log_filter_finalization_node_name} = ""; ); # foreach log_filter_finalization )); #### snapon_add_log_filter_finalizations() #### # # snapon_remove_log_filters() # # Purpose: This removes a log filter from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_log_filters operation node # subroutine(snapon_remove_log_filters(node profile, node attach_operation), ( node filters = attach_operation{"filters"}; node filter; node profile_log_filters = profile{"log"}{"filters"}; # echo("profile_log_filters BEFORE: " . node_as_string(profile_log_filters)); # Remove all specified log filters foreach filter filters ( # Remove the log filter node to the profile # echo("filter: " . node_as_string(filter)); node log_filter_node = profile_log_filters{node_name(filter)}; delete_node(log_filter_node); # echo("Removed log filter '" . node_name(filter) . "'"); ); # foreach filters # echo("profile_log_filters AFTER: " . node_as_string(profile_log_filters)); )); #### snapon_remove_log_filters() #### # # snapon_remove_log_filter_initializations() # # Purpose: This removes a log filter from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_log_filter_initializations operation node # subroutine(snapon_remove_log_filter_initializations(node profile, node attach_operation), ( #echo("snapon_remove_log_filter_initializations()"); node log_filter_initializations = attach_operation{"log_filter_initializations"}; node log_filter_initialization; node profile_log_filter_initializations = profile{"log"}{"filter_initialization"}; # Remove all specified log filters foreach log_filter_initialization log_filter_initializations ( #echo("log_filter_initialization: " . log_filter_initialization); # Remove the log log_filter_initialization node to the profile node log_filter_initialization_node = profile_log_filter_initializations{node_name(log_filter_initialization)}; delete_node(log_filter_initialization_node); ); # foreach log_filter_initializations )); #### snapon_remove_log_filter_initializations() #### # # snapon_remove_log_filter_finalizations() # # Purpose: This removes a log filter from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_log_filter_finalizations operation node # subroutine(snapon_remove_log_filter_finalizations(node profile, node attach_operation), ( #echo("snapon_remove_log_filter_finalizations()"); node log_filter_finalizations = attach_operation{"log_filter_finalizations"}; node log_filter_finalization; node profile_log_filter_finalizations = profile{"log"}{"filter_finalization"}; # Remove all specified log filters foreach log_filter_finalization log_filter_finalizations ( #echo("log_filter_finalization: " . log_filter_finalization); # Remove the log log_filter_finalization node to the profile node log_filter_finalization_node = profile_log_filter_finalizations{node_name(log_filter_finalization)}; delete_node(log_filter_finalization_node); ); # foreach log_filter_finalizations )); #### snapon_remove_log_filter_finalizations() #### # # snapon_add_report_fields() # # Purpose: This adds a report field to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_report_fields operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_report_fields(node snapon, node profile, node attach_operation, node detach_operations), ( node fields = attach_operation{"fields"}; node field; node profile_report_fields = profile{"statistics"}{"report_fields"}; # echo("profile_report_fields BEFORE: " . node_as_string(profile_report_fields)); #echo("attach_operation: " . node_as_string(attach_operation)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_report_fields"; # Add all specified report fields foreach field fields ( if (add_in_snapon(field)) then ( # Add the report field node to the profile # echo("field: " . node_as_string(field)); if (profile_report_fields?{node_name(field)}) then error("Snapon attempted to add report field '" . node_name(field) . "', which already exists"); string name = get_unique_node_name(profile_report_fields, node_name(field)); node field_clone = clone_node(field); rename_node(field_clone, name); string default_field_label; if ("lang_stats.field_labels"?{name}) then default_field_label = "{=capitalize(expand(lang_stats.field_labels." . name . "))=}"; else default_field_label = name; # Set defaults set_node_with_default(snapon, field_clone, field_clone, "label", default_field_label); set_node_with_default(snapon, field_clone, field_clone, "database_field", node_name(field)); set_node_with_default(snapon, field_clone, field_clone, "column_label", ""); set_node_with_default(snapon, field_clone, field_clone, "column_info", ""); set_node_with_default(snapon, field_clone, field_clone, "display_format_type", "string"); set_node_with_default(snapon, field_clone, field_clone, "show_remainder_value", "true"); set_node_with_default(snapon, field_clone, field_clone, "show_min_value", "true"); set_node_with_default(snapon, field_clone, field_clone, "show_max_value", "true"); set_node_with_default(snapon, field_clone, field_clone, "show_total_value", "true"); set_node_with_default(snapon, field_clone, field_clone, "percent_calculation", "sum"); #echo("2field_clone: " . node_as_string(field_clone)); insert_node(profile_report_fields, field_clone, num_subnodes(profile_report_fields)); # echo("Added report field '" . node_name(field) . "'"); #echo("field: " . node_as_string(field)); @detach_operation{"fields"}{name} = ""; ); # if add ); # foreach fields # echo("profile_report_fields AFTER: " . node_as_string(profile_report_fields)); )); #### snapon_add_report_fields() #### # # snapon_remove_report_fields() # # Purpose: This removes a report field from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_report_fields operation node # subroutine(snapon_remove_report_fields(node profile, node attach_operation), ( node fields = attach_operation{"fields"}; node field; node profile_report_fields = profile{"statistics"}{"report_fields"}; # echo("profile_report_fields BEFORE: " . node_as_string(profile_report_fields)); # Remove all specified report fields foreach field fields ( # Remove the report field node to the profile # echo("field: " . node_as_string(field)); node report_field_node = profile_report_fields{node_name(field)}; delete_node(report_field_node); # echo("Removeed report field '" . node_name(field) . "'"); ); # foreach fields # echo("profile_report_fields AFTER: " . node_as_string(profile_report_fields)); )); #### snapon_remove_report_fields() #### # # snapon_add_xref_fields() # # Purpose: This adds a xref field to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_xref_fields operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_xref_fields(node profile, node attach_operation, node detach_operations), ( node fields = attach_operation{"fields"}; node field; node profile_cross_reference_groups = profile{"database"}{"cross_reference_groups"}; # echo("profile_cross_reference_groups BEFORE: " . node_as_string(profile_cross_reference_groups)); string xref_group = @attach_operation{"xref_group"}; # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_xref_fields"; @detach_operation{"xref_group"} = xref_group; # Add all specified xref fields foreach field fields ( # Get the name of the database field we actually added, by looking it up in v.dbfieldnames, which was created in snapon_add_xref_fields. # if (!?'v.dbfieldnames') then # error("Snapon adds database fields to xref, before adding the fields themselves (with add_database_fields)"); # string actual_dbfieldname = @'v.dbfieldnames'{node_name(field)}; string actual_dbfieldname = node_name(field); # echo("field: " . node_name(field)); node profile_cross_reference_group; int xrefgroupnum = 0; foreach profile_cross_reference_group profile_cross_reference_groups ( # echo("profile_cross_reference_group: " . node_name(profile_cross_reference_group)); if (matches_wildcard_expression(node_name(profile_cross_reference_group), xref_group)) then ( # echo("MATCH: " . node_name(profile_cross_reference_groups)); # echo(" Adding field '" . node_name(field) . "' to xref group '" . node_name(profile_cross_reference_group) . "'"); @profile_cross_reference_group{"fields"}{actual_dbfieldname} = ""; # echo("Xref group '" . node_name(profile_cross_reference_group) . "' modified; we need to rebuild it"); # string query = "drop table if exists xref" . xrefgroupnum; # string query = "drop table xref" . xrefgroupnum; # echo("query: " . query); # database_sql_query(query, true, false); force_xref_table_rebuild(profile, xrefgroupnum); ); # if group matches pattern xrefgroupnum++; ); # foreach profile_cross_reference_groups @detach_operation{"fields"}{actual_dbfieldname} = ""; ); # foreach fields # echo("profile_cross_reference_groups AFTER: " . node_as_string(profile_cross_reference_groups)); )); #### snapon_add_xref_fields() #### # # snapon_remove_xref_field() # # Purpose: This removes a xref field from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_xref_fields operation node # subroutine(snapon_remove_xref_fields(node profile, node attach_operation), ( node fields = attach_operation{"fields"}; node field; # echo("profile_cross_reference_groups BEFORE: " . node_as_string(profile_cross_reference_groups)); string xref_group = @attach_operation{"xref_group"}; # Remove all specified xref fields foreach field fields ( node profile_cross_reference_groups = profile{"database"}{"cross_reference_groups"}; # echo("field: " . node_name(field)); node profile_cross_reference_group; int xrefgroupnum = 0; foreach profile_cross_reference_group profile_cross_reference_groups ( # echo("profile_cross_reference_group: " . node_name(profile_cross_reference_group)); if (matches_wildcard_expression(node_name(profile_cross_reference_group), xref_group)) then ( # echo("MATCH: " . node_name(profile_cross_reference_groups)); # echo(" Removing field '" . node_name(field) . "' from xref group '" . node_name(profile_cross_reference_group) . "'"); delete_node(profile_cross_reference_group{"fields"}{node_name(field)}); # echo("Xref group '" . node_name(profile_cross_reference_group) . "' modified; we need to rebuild it"); # save_node(profile); # rewrite_database_config(profile); force_xref_table_rebuild(profile, xrefgroupnum); ); # xref group name matches xrefgroupnum++; ); # foreach profile_cross_reference_groups ); # foreach fields # echo("profile_cross_reference_groups AFTER: " . node_as_string(profile_cross_reference_groups)); )); #### snapon_remove_xref_fields() #### # # snapon_add_xref_groups() # # Purpose: This adds a xref group to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_xref_groups operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_xref_groups(node profile, node attach_operation, node detach_operations), ( node groups = attach_operation{"groups"}; # node group; node profile_cross_reference_groups = profile{"database"}{"cross_reference_groups"}; # echo("profile_cross_reference_groups BEFORE: " . node_as_string(profile_cross_reference_groups)); node xref_groups = attach_operation{"xref_groups"}; #echo("xref_groups: " . node_as_string(xref_groups)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_xref_groups"; # @detach_operation{"xref_group"} = xref_group; # Add all specified xref groups node xref_group; foreach xref_group xref_groups ( #echo("xref_group: " . xref_group); string xref_groupname = node_name(xref_group); node profile_xref_group = clone_node(xref_group); # If add_all_aggregating_fields=true, add all aggregating fields to this xref group if ((!xref_group?{"add_all_aggregating_fields"}) or (@xref_group{"add_all_aggregating_fields"})) then ( #echo("add_all_aggregating_columns"); node profile_report_fields = profile{"statistics"}{"report_fields"}; node profile_database_fields = profile{"database"}{"fields"}; node report_field; foreach report_field profile_report_fields ( if ((!report_field?{"include_field_in_reports_by_default"} or (@report_field{"include_field_in_reports_by_default"})) and report_field?{"database_field"}) then ( string database_field_name = @report_field{"database_field"}; #echo("database field: " . database_field_name); node database_field = profile_database_fields{database_field_name}; #echo("database_field: " . node_as_string(database_field)); if (database_field?{"aggregation_method"} and (@database_field{"aggregation_method"} ne "none")) then ( @profile_xref_group{"fields"}{node_name(database_field)} = ""; ); # if aggregating ); # if database_field ); # foreach report field #echo("columns: " . node_as_string(columns)); delete_node(profile_xref_group{"add_all_aggregating_fields"}); ); # if add_all_aggregating_fields #echo("profile_xref_group: " . node_as_string(profile_xref_group)); insert_node(profile_cross_reference_groups, profile_xref_group, num_subnodes(profile_cross_reference_groups)); int xrefgroupnum = num_subnodes(profile_cross_reference_groups) - 1; force_xref_table_rebuild(profile, xrefgroupnum); @detach_operation{"groups"}{xref_groupname} = ""; ); # foreach groups # echo("profile_cross_reference_groups AFTER: " . node_as_string(profile_cross_reference_groups)); )); #### snapon_add_xref_groups() #### # # snapon_remove_xref_groups() # # Purpose: This removes a xref field from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_xref_fields operation node # subroutine(snapon_remove_xref_groups(node profile, node attach_operation), ( node xref_groups = attach_operation{"xref_groups"}; node profile_cross_reference_groups = profile{"database"}{"cross_reference_groups"}; # echo("profile_cross_reference_groups BEFORE: " . node_as_string(profile_cross_reference_groups)); # Remove all specified xref groups node xref_group; foreach xref_group xref_groups ( delete_node(profile_cross_reference_groups{node_name(xref_group)}); ); # echo("profile_cross_reference_groups AFTER: " . node_as_string(profile_cross_reference_groups)); )); #### snapon_remove_xref_groups() #### # # snapon_add_report_element_columns() # # Purpose: This adds report element columns to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_report_element_column operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_report_element_columns(node profile, node attach_operation, node detach_operations), ( #echo("snapon_add_report_element_columns()"); node columns = attach_operation{"columns"}; node profile_reports = profile{"statistics"}{"reports"}; # echo("profile_reports BEFORE: " . node_as_string(profile_reports)); string report = @attach_operation{"report"}; string report_element = @attach_operation{"report_element"}; # echo("Adding column '" . node_name(columns) . "' to report=" . report . "; report_element=" . report_element); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_report_element_columns"; @detach_operation{"report"} = report; @detach_operation{"report_element"} = report_element; # Add all specified report columns node column; foreach column columns ( # Get the name of the report field we actually added, by looking it up in v.reportfieldnames, which was created in snapon_add_report_fields. # if (!?'v.reportfieldnames') then # error("Snapon adds report fields to report elements, before adding the fields themselves (with add_report_fields)"); # string actual_reportfieldname = @'v.reportfieldnames'{node_name(column)}; string actual_reportfieldname = node_name(column); # echo("column: " . node_name(column)); node profile_report; foreach profile_report profile_reports ( #echo("profile_report: " . profile_report); if (matches_wildcard_expression(node_name(profile_report), report)) then ( node profile_report_elements = profile_report{"report_elements"}; node profile_report_element; foreach profile_report_element profile_report_elements ( if (matches_wildcard_expression(node_name(profile_report_element), report_element)) then ( if (profile_report_element?{"columns"}) then ( #echo('add_in_snapon? column=' . node_as_string(column)); bool add = true; if (column?{"add_condition"}) then ( node add_condition_compiled = compile(@column{"add_condition"}); add = evaluate(add_condition_compiled); #echo("add: " . add); ); if (add) then ( # if require_report_field_columns is listed, check if all required columns exist in this report bool found_all_required_columns = true; if (attach_operation?{"require_report_field_columns"}) then ( #echo("Checking report element " . profile_report_element); #echo("FOUND require_report_field_columns"); node report_element_column; node required_column; #echo("profile_report_columns: " . node_as_string(profile_report_columns)); foreach report_element_column (profile_report_element{"columns"}) ( #echo("report_element_column: " . report_element_column); foreach required_column (attach_operation{"require_report_field_columns"}) ( #echo("required_column: " . required_column . ' [' . @required_column . ']'); if (@report_element_column{"report_field"} eq @required_column) then ( @required_column{"found"} = true; #echo(" FOUND " . @required_column); ); ); # foreach required_column ); # foreach report_element_column # Check if we found all required columns #echo('attach_operation{"require_report_field_columns"}: ' . node_as_string(attach_operation{"require_report_field_columns"})); foreach required_column (attach_operation{"require_report_field_columns"}) ( if (!(@required_column{"found"})) then ( found_all_required_columns = false; # echo("Not adding to " . expand(@profile_report_element{'label'}) . ", because we didn't find required column " . @required_column); ); # if not found @required_column{"found"} = false; ); # foreach required_column ); # if require_report_field_columns #echo("@@ found_all_required_columns: " . found_all_required_columns); if (!found_all_required_columns) then next; #echo("Adding to " . expand(@profile_report_element{'label'}) . "; we found all required fields"); node columns = profile_report_element{"columns"}; if (columns?{node_name(column)}) then error("Snapon attempted to add report column '" . node_name(column) . "', which already exists"); string column_name = get_unique_node_name(columns, node_name(column)); node column_clone = clone_node(column); rename_node(column_clone, column_name); insert_node(columns, column_clone, num_subnodes(columns)); # echo(" Added report column '" . node_name(column) . "' to " . profile_report_element); ); # if add ); # if has columns ); # if report element matches ); # foreach profile_report_element ); # if report matches ); # foreach profile_report @detach_operation{"columns"}{actual_reportfieldname} = ""; ); # foreach columns # echo("profile_reports AFTER: " . node_as_string(profile_reports)); )); ### snapon_add_report_element_columns() #### # # snapon_remove_report_element_columns() # # Purpose: This removes report element columns from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_report_element_column operation node # subroutine(snapon_remove_report_element_columns(node profile, node attach_operation), ( node columns = attach_operation{"columns"}; node profile_reports = profile{"statistics"}{"reports"}; # echo("profile_reports BEFORE: " . node_as_string(profile_reports)); string report = @attach_operation{"report"}; string report_element = @attach_operation{"report_element"}; # echo("Removing column '" . node_name(columns) . "' from report=" . report . "; report_element=" . report_element); # Remove all specified report columns node column; foreach column columns ( # echo("column: " . node_name(column)); node profile_report; foreach profile_report profile_reports ( if (matches_wildcard_expression(node_name(profile_report), report)) then ( node profile_report_elements = profile_report{"report_elements"}; node profile_report_element; foreach profile_report_element profile_report_elements ( if (matches_wildcard_expression(node_name(profile_report_element), report_element)) then ( if (profile_report_element?{"columns"}) then ( node columns = profile_report_element{"columns"}; # Remove any columns which have report_field equal to the column we're removing node profile_report_element_column; foreach profile_report_element_column columns ( if (@profile_report_element_column{"report_field"} eq node_name(column)) then ( delete_node(profile_report_element_column); # echo(" Removed report column '" . node_name(column) . "' from " . profile_report_element); ); ); ); # if has columns ); # if report element matches ); # foreach profile_report_element ); # if report matches ); # foreach profile_report ); # foreach columns # echo("profile_reports AFTER: " . node_as_string(profile_reports)); )); ### snapon_remove_report_element_columns() #### # # snapon_add_reports() # # Purpose: This adds reports to a profile # subroutine(snapon_add_reports(node snapon, node profile, node attach_operation, node detach_operations), ( node reports = attach_operation{"reports"}; node profile_reports = profile{"statistics"}{"reports"}; # echo("profile_reports BEFORE: " . node_as_string(profile_reports)); #echo("snapon_add_reports()"); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); #echo("detach_operation_name: " . detach_operation_name); node detach_operation = detach_operations{detach_operation_name}; #echo("detach_operation: " . detach_operation); @detach_operation{"type"} = "remove_reports"; node reports_to_remove = detach_operation{"reports"}; node reports_menu_to_remove = detach_operation{"reports_menu"}; # Add all specified reports node report; foreach report reports ( # Don't add this report if add_in_snapon evaluates to false if (add_in_snapon(report)) then ( #echo(" report: " . node_as_string(report)); # string report_name = node_name(report); if (profile_reports?{node_name(report)}) then error("Snapon attempted to add report '" . node_name(report) . "', which already exists"); string report_name = get_unique_node_name(profile_reports, node_name(report)); string default_report_label; if ("lang_stats.menu.reports"?{report_name}) then default_report_label = "{=capitalize(expand(lang_stats.menu.reports." . report_name . "))=}"; else default_report_label = report_name; # Get the node of the report we're creating, in the profile @profile_reports{report_name} = ""; node profile_report = profile_reports{report_name}; # Set standard report variables set_node_with_default(snapon, profile_report, report, "label", default_report_label); node report_elements = report{"report_elements"}; node profile_report_elements = profile_report{"report_elements"}; # Add all specified report elements node report_element; foreach report_element report_elements ( # Don't add this report element if add_in_snapon evaluates to false if (add_in_snapon(report)) then ( #echo(" report_element: " . report_element); if (profile_report_elements?{node_name(report_element)}) then error("Snapon attempted to add report element '" . node_name(report_element) . "', which already exists"); string report_element_name = get_unique_node_name(profile_report_elements, node_name(report_element)); # Remember to remove this report on detach reports_to_remove{report_name}{"report_elements"}{report_element_name} = true; # Get the node of the report element we're creating, in the profile @profile_report_elements{report_element_name} = ""; node profile_report_element = profile_report_elements{report_element_name}; # Set the report element type @profile_report_element{"type"} = @report_element{"type"}; #echo("report_element: " . node_as_string(report_element)); # Set standard report element variables set_node_with_default(snapon, profile_report_element, report_element, "label", default_report_label); set_node_with_default(snapon, profile_report_element, report_element, "show_header_bar", false); set_node_with_default(snapon, profile_report_element, report_element, "header", ""); set_node_with_default(snapon, profile_report_element, report_element, "footer", ""); set_node_with_default(snapon, profile_report_element, report_element, "date_filter.df", ""); set_node_with_default(snapon, profile_report_element, report_element, "filter.expression", ""); set_node_with_default(snapon, profile_report_element, report_element, "table_filter_expression", ""); # Handle session_overview parameters if (@report_element{"type"} eq "sessions_overview") then ( set_node_with_default(snapon, profile_report_element, report_element, "session_user_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_date_time_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_id_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_duration_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_events_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_entrances_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_exits_field", ""); ); # if sessions_overview # Handle session_paths parameters if (@report_element{"type"} eq "session_paths") then ( #echo("### session paths"); set_node_with_default(snapon, profile_report_element, report_element, "session_user_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_sequence_number_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_id_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_page_field", ""); ); # if session_paths # Handle session_page_paths parameters if (@report_element{"type"} eq "session_page_paths") then ( set_node_with_default(snapon, profile_report_element, report_element, "session_page_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_date_time_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_id_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_entrances_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_exits_field", ""); ); # if session_page_paths if (report_element?{"columns"}) then ( #echo("Processing columns"); node columns = report_element{"columns"}; # Use the first column as the default report field # string default_report_field = @(columns[0]){"report_field"}; # Get the label from lang_stats.menu.reports, if possible string label = report_element_name; if ("lang_stats.menu.reports"?{report_element_name}) then label = "{=capitalize(expand(lang_stats.menu.reports." . report_element_name . "))=}"; set_node_with_default(snapon, profile_report_element, report_element, "omit_parenthesized_items", false); set_node_with_default(snapon, profile_report_element, report_element, "use_overview_for_totals", false); # set_node_with_default(snapon, profile_report_element, report_element, "report_field", default_report_field); set_node_with_default(snapon, profile_report_element, report_element, "show_graphs", "true"); set_node_with_default(snapon, profile_report_element, report_element, "show_table", "true"); set_node_with_default(snapon, profile_report_element, report_element, "number_of_rows", "10"); set_node_with_default(snapon, profile_report_element, report_element, "sort_by", ""); set_node_with_default(snapon, profile_report_element, report_element, "sort_direction", "descending"); set_node_with_default(snapon, profile_report_element, report_element, "show_remainder_row", "true"); set_node_with_default(snapon, profile_report_element, report_element, "show_averages_row", "false"); set_node_with_default(snapon, profile_report_element, report_element, "show_min_row", "false"); set_node_with_default(snapon, profile_report_element, report_element, "show_max_row", "false"); set_node_with_default(snapon, profile_report_element, report_element, "show_totals_row", "true"); # If there is a pivot table, add all that if (report_element?{"pivot_table"}) then ( set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.show_pivot_table", "true"); set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.report_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.number_of_rows", "11"); set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.sort_direction", "descending"); set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.show_averages_row", "false"); set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.show_min_row", "false"); set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.show_max_row", "false"); ); # if pivot table # If there is are graphs, add all that if (report_element?{"graphs"}) then ( set_node_with_default(snapon, profile_report_element, report_element, "graphs.graph_type", "pie"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.y_axis_height", "200"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.x_axis_length", "200"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.show_3d", "false"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.max_variables", "10"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.sort_all_descending", "true"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.show_legend", "true"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.max_legend_rows", "10"); ); # if pivot table # Get the node of the columns we're creating, in the profile @profile_report_element{"columns"} = ""; node profile_columns = profile_report_element{"columns"}; # If add_all_aggregating_columns=true, add all aggregating report fields to this report if (report_element?{"add_all_aggregating_columns"}) then ( #echo("add_all_aggregating_columns"); node profile_report_fields = profile{"statistics"}{"report_fields"}; node profile_database_fields = profile{"database"}{"fields"}; node report_field; foreach report_field profile_report_fields ( if ((!report_field?{"include_field_in_reports_by_default"} or (@report_field{"include_field_in_reports_by_default"})) and report_field?{"database_field"}) then ( string database_field_name = @report_field{"database_field"}; #echo("database field: " . database_field_name); node database_field = profile_database_fields{database_field_name}; #echo("database_field: " . node_as_string(database_field)); if (database_field?{"aggregation_method"} and (@database_field{"aggregation_method"} ne "none")) then ( node column = new_node(); rename_node(column, node_name(report_field)); @column{"report_field"} = node_name(report_field); insert_node(columns, column, num_subnodes(columns)); ); # if aggregating ); # if database_field ); # foreach report field #echo("columns: " . node_as_string(columns)); ); # if add_all_aggregating_columns node column; foreach column columns ( # Don't add this column if add_in_snapon evaluates to false if (add_in_snapon(column)) then ( #echo("column: " . node_as_string(column)); string column_name = node_name(column); # Get the node of the column we're creating, in the profile @profile_columns{column_name} = ""; node profile_column = profile_columns{column_name}; #echo("BEFORE applying column defaults: column=" . node_as_string(column)); #echo("BEFORE applying column defaults: profile_column=" . node_as_string(profile_column)); set_node_with_default(snapon, profile_column, column, "report_field", ""); set_node_with_default(snapon, profile_column, column, "show_column", true); set_node_with_default(snapon, profile_column, column, "show_percent_column", false); set_node_with_default(snapon, profile_column, column, "show_bar_column", false); set_node_with_default(snapon, profile_column, column, "show_graph", false); #echo("AFTER applying column defaults: profile_column: " . node_as_string(profile_column)); ); # foreach column ); # if add_in_snapon ); # if columns #echo("profile_report_element: " . profile_report_element); #echo("profile_report_element: " . node_as_string(profile_report_element)); ); # if add_in_snapon ); # foreach report element ); # if add_in_snapon ); # foreach report node profile_reports_menu = profile{"statistics"}{"reports_menu"}; # This sub-subroutine recursively adds a section of the reports menu, as specified in the snapon subroutine(add_reports_menu_items(node snapon, node reports_menu_subnode, node profile_reports_menu_subnode, node detach_operations_subnode), ( # echo("reports_menu_subnode: " . reports_menu_subnode . ": " . node_as_string(reports_menu_subnode)); node reports_menu_item; foreach reports_menu_item reports_menu_subnode ( if (add_in_snapon(reports_menu_item)) then ( # if (profile_reports_menu_subnode?{node_name(reports_menu_item)}) then ( # # No need for an error; just don't add it again (or remove it when we remove the snapon) # error("Snapon attempted to add report menu item '" . node_name(reports_menu_item) . "', which already exists"); # ); # # If the reports menu item doesn't exist, add it # else ( # Compute the node name in the reports menu. If this is a group, just use the name (which will cause new reports to be added to existing groups). If it's a report, get a new node name (which will cause reports with the same name to appear twice). string reports_menu_item_name; if (reports_menu_item?{"items"}) then ( reports_menu_item_name = node_name(reports_menu_item); ); else ( reports_menu_item_name = get_unique_node_name(profile_reports_menu_subnode, node_name(reports_menu_item)); ); # Remember to remove this item on detach # @detach_operations_subnode{reports_menu_item_name} = true; @profile_reports_menu_subnode{reports_menu_item_name} = ""; node profile_reports_menu_item = profile_reports_menu_subnode{reports_menu_item_name}; #echo("profile_reports_menu_item: " . node_as_string(profile_reports_menu_item)); string menu_item_label = reports_menu_item_name; # If this has items, it must be a group. Handle it recursively. if (reports_menu_item?{"items"}) then ( # echo("Detected group: " . reports_menu_item_name); # Get the label from lang_stats.menu.groups, if possible if ("lang_stats.menu.groups"?{reports_menu_item_name}) then menu_item_label = "{=capitalize(expand(lang_stats.menu.groups." . reports_menu_item_name . "))=}"; #echo("reports_menu_item?{'label'}: " . reports_menu_item?{'label'} ); set_node_with_default(snapon, profile_reports_menu_item, reports_menu_item, "label", menu_item_label); #echo("profile_reports_menu_item: " . node_as_string(profile_reports_menu_item)); add_reports_menu_items(snapon, reports_menu_item{"items"}, profile_reports_menu_item{"items"}, detach_operations_subnode{reports_menu_item_name}{"items"}); #echo("2 profile_reports_menu_item: " . node_as_string(profile_reports_menu_item)); ); # if has items # This isn't a group; handle it as a normal report else ( # echo("Detected report link: " . reports_menu_item_name); @profile_reports_menu_item{"report"} = reports_menu_item_name; # Remember to remove this item on detach @detach_operations_subnode{reports_menu_item_name} = true; # Get the label from lang_stats.menu.reports, if possible if ("lang_stats.menu.reports"?{reports_menu_item_name}) then menu_item_label = "{=capitalize(expand(lang_stats.menu.reports." . reports_menu_item_name . "))=}"; # Set the values of the "show" variables set_node_with_default(snapon, profile_reports_menu_item, reports_menu_item, "label", menu_item_label); set_node_with_default(snapon, profile_reports_menu_item, reports_menu_item, "show_in_dynamic_reports", true); set_node_with_default(snapon, profile_reports_menu_item, reports_menu_item, "show_in_static_reports", true); ); # if no items # ); # if doesn't exist #echo("reports_menu_item_name: " . reports_menu_item_name); ); # if add_in_snapon ); # reports_menu_items )); #### add_reports_menu_items() #### node reports_menu = attach_operation{"reports_menu"}; add_reports_menu_items(snapon, reports_menu, profile_reports_menu, reports_menu_to_remove); # echo("profile_reports AFTER: " . node_as_string(profile_reports)); # echo("profile_reports_menu AFTER: " . node_as_string(profile_reports_menu)); )); ### snapon_add_reports() #### # # snapon_remove_reports() # # Purpose: This removes report element columns from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_report operation node # subroutine(snapon_remove_reports(node profile, node attach_operation), ( node reports = attach_operation{"reports"}; node profile_reports = profile{"statistics"}{"reports"}; # Remove all specified reports node report; foreach report reports ( string report_name = node_name(report); node report_elements = report{"report_elements"}; node report_element; foreach report_element report_elements ( string report_element_name = node_name(report_element); delete_node(profile_reports{report_name}{"report_elements"}{report_element_name}); ); # foreach report_element delete_node(profile_reports{report_name}); ); # foreach report node reports_menu = attach_operation{"reports_menu"}; # This sub-subroutine recursively removes a section of the reports menu, as specified in the snapon subroutine(remove_reports_menu_items(node reports_menu_subnode, node profile_reports_menu_subnode), ( # echo("reports_menu_subnode: " . reports_menu_subnode . ": " . node_as_string(reports_menu_subnode)); node reports_menu_item; foreach reports_menu_item reports_menu_subnode ( string reports_menu_item_name = node_name(reports_menu_item); @profile_reports_menu_subnode{reports_menu_item_name} = ""; node profile_reports_menu_item = profile_reports_menu_subnode{reports_menu_item_name}; #echo("profile_reports_menu_item: " . node_as_string(profile_reports_menu_item)); string label = reports_menu_item_name; # If this has items, it must be a group. Handle it recursively. if (reports_menu_item?{"items"}) then ( remove_reports_menu_items(reports_menu_item{"items"}, profile_reports_menu_item{"items"}); if (num_subnodes(profile_reports_menu_item{"items"}) == 0) then ( delete_node(profile_reports_menu_item); ); #echo("profile_reports_menu_item{items} size: " . num_subnodes(profile_reports_menu_item{"items"})); ); # if has items # This isn't a group; handle it as a normal report else ( # echo("Detected report link: " . reports_menu_item_name); delete_node(profile_reports_menu_item); ); # if no items #echo("reports_menu_item_name: " . reports_menu_item_name); ); # reports_menu_items )); #### remove_reports_menu_items() #### node profile_reports_menu = profile{"statistics"}{"reports_menu"}; remove_reports_menu_items(reports_menu, profile_reports_menu); # echo("profile_reports AFTER: " . node_as_string(profile_reports)); )); ### snapon_remove_reports() #### # # set_task_action() # # Purpose: This sets the action for this task, by writing IPC/Task-#-Action # # Parameters: action: the action to write # subroutine(set_task_action(string action), ( # Get our task ID string taskID = current_task_id(); # string database_directory = get_database_directory(profile); string ipcDirectory = internal.LOGANALYSISINFO_DIRECTORY . "IPC"; string taskActionPathname = ipcDirectory . internal.directory_divider . "Task-" . taskID . "-Action"; write_file(taskActionPathname, action); # echo("Set task action to '" . action . "' (" . taskActionPathname . ")"); )); #### set_task_action() #### # # attach_snapon() # # Purpose: This attaches a snapon to a profile # # Parameters: profile: the profile to attached to # snapon_node: the snapon node to attach. This is a clone of the original snapon node which must have the same node name as the original node name! # attached_snapon_name: the node name as it is attached in the profile.snapons node. # subroutine(attach_snapon(node profile, node snapon_node, string attached_snapon_name), ( # echo("attach_snapon()"); # Remember what action this is, for progress reporting @'command_line.action' = 'attach_snapon'; #echo("snapon_node: " . node_as_string(snapon_node)); node snapons = profile{"snapons"}; # There must be a label in a snapon if (!snapon_node?{"label"} or (@snapon_node{"label"} eq "(unspecified)")) then error("Snapon " . snapon_node . " does not include required label"); node parameters = snapon_node{"parameters"}; # echo("parameters: " . node_as_string(parameters)); resolve_variables(snapon_node, parameters); # Resolve {x= =x} sections in to plain { = = }. resolve_escaped_salang_sections(snapon_node); #echo("resolved node: " . node_as_string(snapon_node)); # Make sure this snapon isn't already attached, with the same label node snapon; string label; label = @snapon_node{"label"}; #echo("label: " . label); foreach snapon snapons ( #echo("snapon: " . snapon); if (snapon?{"label"} and (@snapon{"label"} eq label)) then ( error("A snapon with label '" . label . "' already exists; please choose a different label"); ); ); # foreach snapon # if (snapons?{node_name(snapon_node)}) then # error("Snapon " . node_name(snapon_node) . " is already attached; doing nothing"); #LM # If there is no snapon using the snapon as its name, use that. # KHP, disabled snapon_node_name code because the callee function requires # the snapon_node_name of the profile, so it is given as argument. snapon = snapons{attached_snapon_name}; # string snapon_node_name = node_name(snapon_node); # if (!snapons?{snapon_node_name}) then ( # snapon = snapons{snapon_node_name}; # ); # Otherwise, count up until we find an unused snapon name # else ( # int snaponnum = 2; # while (snapons?{snapon_node_name . snaponnum}) # snaponnum++; # snapon = snapons{snapon_node_name . snaponnum}; # label = @snapon_node{"label"} . ' ' . snaponnum; # ); # if name used #echo("snapon: " . snapon); #echo("label: " . label); # Save the lable of this snapon instance @snapon{"label"} = label; # Save the source snapon name # KHP - added source_snapon_name because the node_name of the cloned snapon node is different than the source node name # 2010-03-11 - GMF - Switched back (removed source_snapon_name), because I modified handle_attach_snapon.cfv so it keeps the node name in the clone. @snapon{"snapon_name"} = node_name(snapon_node); # @snapon{"snapon_name"} = source_snapon_name; # Get a node to save the detach operations in, in the profile. node detach_operations = snapon{"detach_operations"}; # Mark the action for this task as "attaching_snapon" to the UI knows what we're doing. set_task_action("attaching_snapon"); #echo("0 log.fields: " . node_as_string(profile{"log.fields"})); # Apply all the "attach" operations node attach_operations = snapon_node{"attach_operations"}; #echo("attach_operations: " . node_as_string(attach_operations)); node attach_operation; foreach attach_operation attach_operations ( string type = @attach_operation{"type"}; # echo("type: " . type); # Handle add_log_fields if (type eq "add_log_fields") then snapon_add_log_fields(snapon_node, profile, attach_operation, detach_operations); # Handle add_database_fields else if (type eq "add_database_fields") then snapon_add_database_fields(snapon_node, profile, attach_operation, detach_operations); else if (type eq "add_database_filters") then snapon_add_database_filters(profile, attach_operation, detach_operations); else if (type eq "add_log_filters") then snapon_add_log_filters(profile, attach_operation, detach_operations); else if (type eq "add_log_filter_initializations") then snapon_add_log_filter_initializations(profile, attach_operation, detach_operations); else if (type eq "add_log_filter_finalizations") then snapon_add_log_filter_finalizations(profile, attach_operation, detach_operations); else if (type eq "add_report_fields") then snapon_add_report_fields(snapon_node, profile, attach_operation, detach_operations); else if (type eq "add_xref_fields") then snapon_add_xref_fields(profile, attach_operation, detach_operations); else if (type eq "add_xref_groups") then snapon_add_xref_groups(profile, attach_operation, detach_operations); else if (type eq "add_report_element_columns") then snapon_add_report_element_columns(profile, attach_operation, detach_operations); else if (type eq "add_reports") then snapon_add_reports(snapon_node, profile, attach_operation, detach_operations); else if (type eq "edit_profile_node") then snapon_edit_profile_node(snapon_node, profile, attach_operation, detach_operations); else if (type eq "add_snapons") then snapon_add_snapons(profile, attach_operation, detach_operations); else if (type eq "execute_expression") then snapon_execute_expression(profile, attach_operation, detach_operations); else ( error("attach_snapon: unknown type '" . type . "'"); ); #echo("Done with attach operation"); #echo("log.fields: " . node_as_string(profile{"log.fields"})); ); # foreach attach operations # Add this to the list of attached snapons #echo("node_name(snapon_node): " . node_name(snapon_node)); # snapons{node_name(snapon_node)}{"name"} = node_name(snapon_node); # Rewrite the database config file #echo("Writing config"); rewrite_database_config(profile); # Save the modified profile #echo("Saving profile"); #echo("profile node: " . node_as_string(profile)); save_node(profile); #echo("Saved profile"); # Apply the database filters for this snap-on, if the main table exists if (database_table_exists(get_database_table_name(profile, "main_table"))) then ( node options = new_node(); @options{1} = "background"; @options{2} = "-p"; @options{3} = internal.profile_name; @options{4} = "-a"; @options{5} = "udf"; @options{6} = "-fr"; @options{7} = "true"; @options{8} = "volatile.snapon"; #echo("snapon_node: " . snapon_node); @options{9} = node_name(snapon_node); @options{10} = "-v"; @options{11} = "egboUh"; # echo("options=" . node_as_string(options)); int res = exec("", options, true); # echo("res=" . res); ); #echo("Returning from attach_snapon()1"); )); #### attach_snapon() #### # # detach_snapon_instance() # # Purpose: This detaches an instance of a snapon from a profile # # Parameters: profile: the profile to detached from # snapon_instance_name: the snapon node to detach # subroutine(detach_snapon_instance(node profile, string snapon_instance_name), ( # Run a dummy query, which does nothing, to force the database to be fully loaded before we start messing with it. drop_table_if_exists("table_which_doesnt_exist"); # database_sql_query("create table snapon_dummy", true, false); # database_sql_query("drop table snapon_dummy", true, false); # Mark the action for this task as "detaching_snapon" to the UI knows what we're doing. set_task_action("detaching_snapon"); # Make sure this snapon is attached node snapons = profile{"snapons"}; if (!snapons?{snapon_instance_name}) then error("Snapon instance " . snapon_instance_name . " is not attached; doing nothing"); #LM node snapon_instance = snapons{snapon_instance_name}; # Apply all the "detach" operations node detach_operations = snapon_instance{"detach_operations"}; # echo("detach_operations: " . node_as_string(detach_operations)); node detach_operation; foreach detach_operation detach_operations ( # echo("detach_operation: " . node_as_string(detach_operation)); string type = @detach_operation{"type"}; # echo("type: " . type); # Handle remove_database_fields if (type eq "remove_database_fields") then snapon_remove_database_fields(profile, detach_operation); else if (type eq "remove_log_fields") then snapon_remove_log_fields(profile, detach_operation); else if (type eq "remove_database_filters") then snapon_remove_database_filters(profile, detach_operation); else if (type eq "remove_log_filters") then snapon_remove_log_filters(profile, detach_operation); else if (type eq "remove_log_filter_initializations") then snapon_remove_log_filter_initializations(profile, detach_operation); else if (type eq "remove_log_filter_finalizations") then snapon_remove_log_filter_finalizations(profile, detach_operation); else if (type eq "remove_report_fields") then snapon_remove_report_fields(profile, detach_operation); else if (type eq "remove_xref_fields") then snapon_remove_xref_fields(profile, detach_operation); else if (type eq "remove_xref_groups") then snapon_remove_xref_groups(profile, detach_operation); else if (type eq "remove_report_element_columns") then snapon_remove_report_element_columns(profile, detach_operation); else if (type eq "remove_reports") then snapon_remove_reports(profile, detach_operation); else if (type eq "unedit_profile_node") then snapon_unedit_profile_node(profile, detach_operation); else if (type eq "remove_snapons") then snapon_remove_snapons(profile, detach_operation); else if (type eq "remove_database_snapons") then snapon_remove_snapons(profile, detach_operation); # Expressions can't be undone else if (type eq "execute_expression") then ( ); else ( error("detach_snapon: unknown type '" . type . "'"); ); #echo("rewriting after detach op " . type); rewrite_database_config(profile); ); # foreach detach operations # Remove this from the list of attached snapon instances delete_node(snapon_instance); # Rewrite the database config file #echo("rewriting after detach"); rewrite_database_config(profile); # Save the modified profile save_node(profile); # Apply the database filters for internal_optimize, if the main table exists. Otherwise, fields removed by this snapon # will not be propagated to xref tables. if (database_table_exists(get_database_table_name(profile, "main_table"))) then ( node options = new_node(); @options{1} = "background"; @options{2} = "-p"; @options{3} = internal.profile_name; @options{4} = "-a"; @options{5} = "udf"; @options{6} = "-fr"; @options{7} = "true"; @options{8} = "volatile.snapon"; @options{9} = "internal_optimize"; @options{10} = "-v"; @options{11} = "egboUh"; # echo("options=" . node_as_string(options)); int res = exec("", options, true); # echo("res=" . res); ); )); #### detach_snapon_instance() ####