# Copyright (c) 2010 Flowerfire, Inc. All Rights Reserved. autodesk_license_manager_enhanced = { plugin_version = "1.4.3" info.1.manfacturer = "Autodesk" info.1.device = "Network License Manager (Ehanced Reports)" info.1.version = "" # 2008-05-05 - 1.0 - KBB - Initial creation. This plug-in uses data from three log files. # One is primary and the other two provide additional data that will be used until the # file is encountered again and it changes. This data is saved in the node (file) autodesk.cfg. # 2008-05-29 - 1.0.1 - KBB - Improved autodetect after receiving sample without options file line. # 2008-06-21 - 1.2 - KBB - Corrected problem with negative duration and missing dates caused by # some TIMESTAMPs being skipped because the first characer was space instead of 0. Changed the # saving of start times from collected fields to nodes so that they can be used when the # database is updated. # 2008-06-23 - 1.3 - KBB - Changed collection of license information to allow multiple licenses, # which are matched to the events by the product ID. Other changes to accomodate more complex license # files. Created custom report with all product information in separate columns. Added product_name to # key for saving start times. Added constant for number of allowed license files. Error is printed # if number is exceeded. # 2008-06-30 - 1.3.1 - KBB - Added support for a format variation in the license file and lowercased # product name for nodes in case it is different between logs and license file. # 2008-07-18 - 1.4 - KBB - Added custom reports provided by GITS. # 2008-08-04 - 1.4.1 - KBB - Removed groups and reorderd reports in reports menu. # 2008-08-11 - 1.4.2 - KBB - Changed some labels for easier localization. Added mapping for value # of action field to allow translation. # 2008-08-11 - 1.4.3 - KBB - Changed filters on action value to use mapping. That means mapping must # exist or profile creation will fail. # The name of the log format log.format.format_label = "Autodesk Network License Manager (FlexLM) Log Format (Enhanced Reports)" log.miscellaneous.log_data_type = "generic" log.miscellaneous.log_format_type = "other" # The log is in this format if any of the first ten lines match this regular expression ##DeptpName #ComputerName #UserName #IP_Address #VENDOR adskflex option="C:\Program Files\Autodesk Network License Manager\License\adskflex.opt" port=2080 #13:34:14 (adskflex) Using options file: "C:\Program Files\Autodesk Network License Manager\License\adskflex.opt" #13:34:10 (lmgrd) License file(s): C:\AutoDesk\123-45678901(1).lic #16:56:31 (lmgrd) License file(s): C:\Program Files\Autodesk Network License Manager\License\123-45678901(9).lic log.format.autodetect_expression = ` matches_regular_expression(volatile.log_data_line, '^\\#DeptpName \\#ComputerName \\#UserName \\#IP_Address$') or matches_regular_expression(volatile.log_data_line, '^VENDOR [^ ]+ option="[^"]+" port=[0-9]+$') or matches_regular_expression(volatile.log_data_line, '^[0-9]{2}:[0-9]{2}:[0-9]{2} \\([^)]+\\) Using options file: "[^"]+"$') or matches_regular_expression(volatile.log_data_line, '^[0-9]{2}:[0-9]{2}:[0-9]{2} \\([^)]+\\) License file\\(s\\): ') ` log.format.autodetect_lines = 100; # The format of dates and times in this log log.format.date_format = "m/d/yyyy" log.format.time_format = "auto" # All log field parsing will be done using the parsing filters log.format.parse_only_with_filters = "true" # Log fields log.fields = { date = "" time = "" # from debug file user = "" action = "" reason = "" duration = "" # calculated # from dept file department = "" #computer = "" #username = "" ip_address = "" # from license file license_server_name = "" license_server_mac_address = "" product_name = "" maximum_concurrent_users = "" license_activation_date = "" product_serial_number = "" } # log.fields log.filter_initialization = ` int license_file_limit = 3; autodesk.timestamp = epoc_to_date_time(now()); node autodesk = 'autodesk.timestamp'; v.date = ''; v.first_time = 0; v.product_name = ''; ` # Log Parsing Filters log.parsing_filters.parse = ` v.line = current_log_line(); # This needs to be done with nodes because already processed, unchanged # license files will not be seen during a database update. v.path = current_log_pathname(); if (ends_with(v.path, '.lic')) then ( v.path = replace_all(v.path, '.', '_dot_'); int license_file_count = 1; if (!subnode_exists('autodesk', 'license_files')) then ( set_subnode_value('autodesk', 'license_files', ""); ); if (subnode_exists('autodesk.license_files', v.path)) then ( # Failing here would indicate that autodesk.cfg had been edited or the limit had been decreased. if (num_subnodes('autodesk.license_files') > license_file_limit) then ( save_node('autodesk'); error(lang_admin.messages.too_many_license_files_error . '
' . lang_admin.messages.allowed_license_files_message . license_file_limit); ); ); else ( if (num_subnodes('autodesk.license_files') < license_file_limit) then ( set_subnode_value('autodesk.license_files', v.path, ""); ); # This is the more normal failure; an extra license file has been encountered. else ( save_node('autodesk'); error(lang_admin.messages.too_many_license_files_error . '
' . lang_admin.messages.allowed_license_files_message . license_file_limit); ); ); ); ##DeptpName #ComputerName #UserName #IP_Address #Design Verthandi Administrator 192.168.3.33 #Design Gethen Estraven 192.168.3.34 #Structure Urth Severian 192.168.3.53 #Structure Urth Jonas 192.168.3.53 if (matches_regular_expression(v.line, '^([^ ]+) ([^ ]+) ([^ ]+) ([0-9.]+)$')) then ( v.user = lowercase($3 . '@' . $2); set_subnode_value('autodesk', v.user, ""); set_subnode_value('autodesk.' . v.user, 'department', $1); set_subnode_value('autodesk.' . v.user, 'ip_address', $4); ); # department file #SERVER earthsea 0040250D5207 #USE_SERVER #VENDOR adskflex option="C:\Program Files\Autodesk Network License Manager\License\adskflex.opt" port=2080 #PACKAGE 64300ACD_F adskflex 1.000 COMPONENTS="57600ACD_2009_0F \ # 54600ACD_2008_0F 51200ACD_2007_0F 48800ACD_2006_0F" \ # OPTIONS=SUITE SUPERSEDE ISSUED=25-Apr-2008 SIGN="0C3D 8644 \ # E012 3B07 8548 004B 0454 C3C7 CD0C C49E AFB0 5DEB 39AA AD4A \ # E123 0AFF EB90 0A37 E96D AB1F 7CD4 388B 3EBF 3318 6748 949C \ # B867 D272 7909 DCED" SIGN2="0667 0D99 87E8 4184 BE69 5933 06F9 \ # A915 D005 363C 05DA C2DD C465 857F 9982 0BBC 86D5 D7D5 3DB9 \ # E0C9 3501 5911 2B6D E827 6B4E 8766 F4CE 3539 3CCB FFAC" #INCREMENT 64300ACD_F adskflex 1.000 15-jun-2008 1 \ # VENDOR_STRING=nfr:extendable BORROW=4320 SUPERSEDE \ # DUP_GROUP=UH ISSUED=15-Apr-2008 SN=354-94060732 SIGN="1CC5 \ # 3A89 D40F EF00 8355 BA61 A4C7 238A 0232 F6CC 487E 423F F0EC \ # Variant without date: #INCREMENT 54900AMECH_PP_2008_0F adskflex 1.000 permanent 9 \ else if (matches_regular_expression(v.line, '^SERVER ([^ ]+) ([0-9A-Da-d]{12})$')) then ( set_subnode_value('autodesk', 'license_server_name', $1); set_subnode_value('autodesk', 'license_server_mac_address', $2); ); else if (matches_regular_expression(v.line, '^INCREMENT ([^ ]+) [^ ]+ [0-9.]+ [^ ]+ ([0-9]+) \\\\\\\\\$')) then ( v.product_name = lowercase($1); set_subnode_value('autodesk', v.product_name, ""); set_subnode_value('autodesk.' . v.product_name, 'maximum_concurrent_users', $2); ); else if (matches_regular_expression(v.line, '^PACKAGE [^ ]+ [^ ]+ [0-9.]+ COMPONENTS=')) then ( # Clear the product name to avoid changing the date for # the previous product when ISSUED is encountered. v.product_name = ""; ); # The product name should have been seen by now, but skip this if it hasn't, # or if PACKAGE has been seen since. # These are usually on the same line, but not always. else if (matches_regular_expression(v.line, '[ ](SN=|ISSUED=)') and (v.product_name ne '') and subnode_exists('autodesk', v.product_name)) then ( if (matches_regular_expression(v.line, 'SN=([^ ]+) ?')) then ( set_subnode_value('autodesk.' . v.product_name, 'product_serial_number', $1); ); if (matches_regular_expression(v.line, 'ISSUED=([^ ]+) ?')) then ( set_subnode_value('autodesk.' . v.product_name, 'license_activation_date', $1); ); ); #13:34:10 (lmgrd) FLEXnet Licensing (v11.4.0.0 build 31341) started on gits-kenny (IBM PC) (4/28/2008) #13:34:16 (lmgrd) TIMESTAMP 4/30/2008 else if (matches_regular_expression(v.line, '^[0-9 ][0-9]:[0-9]{2}:[0-9]{2} \\\\([^)]*\\\\) FLEXnet Licensing \\\\([^)]*\\\\) started on [^ ]+ \\\\([^)]+\\\\) \\\\(([0-9]{1,2}/[0-9]{1,2}/[0-9]{4})\\\\)$') or matches_regular_expression(v.line, '^[0-9 ][0-9]:[0-9]{2}:[0-9]{2} \\\\([^)]*\\\\) TIMESTAMP ([0-9]{1,2}/[0-9]{1,2}/[0-9]{4})$')) then ( v.date = $1; ); #15:03:13 (adskflex) OUT: "54600ACD_2008_0F" Administrator@earthsea #15:03:42 (adskflex) DENIED: "54600ACD_2008_0F" Administrator@urth (Licensed number of users already reached. (-4,342)) #15:03:42 (adskflex) DENIED: "54600ACD_2008_0F" Administrator@urth (Licensed number of users already reached. (-4,342)) #15:04:01 (adskflex) DENIED: "54600ACD_2008_0F" Administrator@urth (Licensed number of users already reached. (-4,342)) #15:04:01 (adskflex) DENIED: "54600ACD_2008_0F" Administrator@urth (Licensed number of users already reached. (-4,342)) #15:06:20 (adskflex) IN: "54600ACD_2008_0F" Administrator@earthsea #15:06:21 (adskflex) OUT: "54600ACD_2008_0F" Administrator@urth #15:08:11 (adskflex) DENIED: "54600ACD_2008_0F" Administrator@earthsea (Licensed number of users already reached. (-4,342)) #15:08:11 (adskflex) DENIED: "54600ACD_2008_0F" Administrator@earthsea (Licensed number of users already reached. (-4,342)) #15:09:51 (adskflex) IN: "54600ACD_2008_0F" Administrator@urth else if (matches_regular_expression(v.line, '^ ?([0-9]{1,2}:[0-9]{2}:[0-9]{2}) \\\\([^)]+\\\\) ([A-Z]+): "([^"]+)" (([^ ]+)@([^ ]+)) *(\\\\((.*)\\\\))?$')) then ( v.action = $2; v.product_name = lowercase($3); v.user = lowercase($4); # for access to node and key below set_collected_field('', 'time', $1); set_collected_field('', 'date', v.date); #set_collected_field('', 'action', v.action); set_collected_field('', 'product_name', $3); set_collected_field('', 'user', $4); set_collected_field('', 'reason', $8); if (node_exists('lang_stats.log_formats.autodesk_network_license_manager.action.' . v.action)) then ( set_collected_field('', 'action', node_value('lang_stats.log_formats.autodesk_network_license_manager.action.' . v.action)); ); else ( set_collected_field('', 'action', v.action); ); if (v.first_time == 0) then ( v.first_time = date_time_to_epoc(get_collected_field('', 'date_time')); ); if (subnode_exists('autodesk', v.user)) then ( #set_collected_field('', 'computer', v.computer); #set_collected_field('', 'username', node_value('autodesk.' . v.computer . '.username')); set_collected_field('', 'ip_address', node_value('autodesk.' . v.user . '.ip_address')); set_collected_field('', 'department', node_value('autodesk.' . v.user . '.department')); ); if (subnode_exists('autodesk', 'license_server_name')) then ( set_collected_field('', 'license_server_name', node_value('autodesk.license_server_name')); ); if (subnode_exists('autodesk', 'license_server_mac_address')) then ( set_collected_field('', 'license_server_mac_address', node_value('autodesk.license_server_mac_address')); ); int max_users = 0; if (subnode_exists('autodesk', v.product_name)) then ( if (subnode_exists('autodesk.' . v.product_name, 'license_activation_date')) then ( set_collected_field('', 'license_activation_date', node_value('autodesk.' . v.product_name . '.license_activation_date')); ); if (subnode_exists('autodesk.' . v.product_name, 'product_serial_number')) then ( set_collected_field('', 'product_serial_number', node_value('autodesk.' . v.product_name . '.product_serial_number')); ); if (subnode_exists('autodesk.' . v.product_name, 'maximum_concurrent_users')) then ( max_users = node_value('autodesk.' . v.product_name . '.maximum_concurrent_users'); # used below set_collected_field('', 'maximum_concurrent_users', max_users); ); ); # Calculate duration. # # There is no true key, so overlapping IN/OUT events for the same user will be # assumed to end in the same order they started. # # Action OUT means take a license out of the license pool, so it is the START. # Action IN means restore a license to the license pool, so it is the END. # Save the start time if this is an OUT event. v.base_key = v.user . '_' . v.product_name . '_'; if (v.action eq 'OUT') then ( int i = 0; v.key = v.base_key . i; # Note that keys are separate from users so that it isn't necessary to check # for two nodes and in case the user was not in the Department file. while (subnode_exists('autodesk', v.key)) ( i++; v.key = v.base_key . i; ); set_subnode_value('autodesk', v.key, date_time_to_epoc(get_collected_field('', 'date_time'))); ); # OUT # Calculate the duration if this is an IN event and we have a start time for the OUT event. else if (v.action eq 'IN') then ( int start_time = 0; int i = 0; v.key = v.base_key . i; while (subnode_exists('autodesk', v.key)) ( start_time = node_value('autodesk.' . v.key); i++; v.key = v.base_key . i; ); if (start_time == 0) then ( start_time = v.first_time; # Use the beginning of the log ); if (start_time > 0) then ( i--; v.key = v.base_key . i; int end_time = date_time_to_epoc(get_collected_field('', 'date_time')); set_collected_field('', 'duration', 0.0 + (end_time - start_time)); if (subnode_exists('autodesk', v.key)) then ( delete_node('autodesk.' . v.key); # clear start_time ); ); ); # IN accept_collected_entry('', false); ); ` log.filter_finalization = `save_node('autodesk');` # Database fields database.fields = { date_time = "" hour_of_day = "" day_of_week = "" # from debug file user = "" # username@computer action = "" reason = "" # from dept file department = "" #computer = "" #username = "" ip_address = "" # from license file license_server_name = "" license_server_mac_address = "" product_name = "" maximum_concurrent_users = "" license_activation_date = "" product_serial_number = "" } # database.fields # Log Filters log.filters = { mark_entry = { label = '$lang_admin.log_filters.mark_entry_label' comment = '$lang_admin.log_filters.mark_entry_comment' value = 'events = 1;' } # mark_entry } # log.filters database.numerical_fields = { events = { default = true requires_log_field = false entries_field = true } # events duration = { default = true type = float display_format_type = duration_compact } # duration } # database.numerical_fields create_profile_wizard_options = { # Specify the reports menu manually manual_reports_menu = true # How the reports should be grouped in the report menu report_groups = { # authentication_group = { # items = { denial_by_product = { label = "{=capitalize(print(lang_stats.field_labels.denial_by_product))=}" #filter = "action matches 'DENIED'" filter = "action matches '{=lang_stats.log_formats.autodesk_network_license_manager.action.DENIED=}'" columns = { 0.field_name = "user" 1.field_name = "product_name" 2.field_name = "events" 3.field_name = "duration" } # columns sub_table = "" } # user_auth_failure_count denial_by_hour_of_day = { label = "{=capitalize(print(lang_stats.field_labels.denial_by_hour_of_day))=}" #filter = "action matches 'DENIED'" filter = "action matches '{=lang_stats.log_formats.autodesk_network_license_manager.action.DENIED=}'" columns = { 0.field_name = "hour_of_day" 1.field_name = "user" 2.field_name = "events" 3.field_name = "duration" } # columns sub_table = "" } # denial_by_hour_of_day user_by_department = { label = "{=capitalize(print(lang_stats.field_labels.user_by_department))=}" # Changed to variable for complete label to ease Chinese translation. #label = "{=capitalize(print(database.fields.user.label)) . lang_stats.multi_column_report_divider . database.fields.department.label=}" columns = { 0.field_name = "department" 1.field_name = "user" 2 = { field_name = "events" show_graph = true } 3 = { field_name = "duration" show_graph = true } } # columns sub_table = "" graphs.graph_type = "pie" } # user_by_department authentication_by_user = { label = "{=capitalize(print(lang_stats.field_labels.authentication_by_user))=}" columns = { 0.field_name = "user" 1.field_name = "action" 2.field_name = "events" 3.field_name = "duration" } # columns sub_table = "" } # authentication_by_user authentication_by_product = { label = "{=capitalize(print(lang_stats.field_labels.authentication_by_product))=}" columns = { 0.field_name = "product_name" 1.field_name = "action" 2 = { field_name = "events" show_graph = true } 3.field_name = "duration" } # columns sub_table = "" graphs.graph_type = "line" } # authentication_by_product # } # items # } # authentication_group # information_group = { # items = { product_information = { omit_parenthesized_items = "false" label = "{=capitalize(print(lang_stats.field_labels.product_information))=}" columns = { 0.field_name = "product_name" 1.field_name = "maximum_concurrent_users" 2.field_name = "license_activation_date" 3.field_name = "product_serial_number" 4.field_name = "events" 5.field_name = "duration" } # columns } # product_information authentication_server = { omit_parenthesized_items = "false" label = "{=capitalize(print(lang_stats.field_labels.authentication_server))=}" columns = { 0.field_name = "license_server_name" 1.field_name = "license_server_mac_address" 3.field_name = "events" 4.field_name = "duration" } # columns } # authentication_server user = { omit_parenthesized_items = "false" label = "{=capitalize(pluralize(print(lang_stats.field_labels.user)))=}" columns = { 0.field_name = "user" 1.field_name = "department" 2.field_name = "ip_address" 3.field_name = "events" 4.field_name = "duration" } # columns } # user action = { omit_parenthesized_items = "false" label = "{=capitalize(pluralize(print(lang_stats.field_labels.action)))=}" columns = { 0.field_name = "action" 1.field_name = "reason" 2.field_name = "events" 3.field_name = "duration" } # columns } # action # } # } # information_group log_detail = true single_page_summary = true date_time_group = { items = { date_time = { label = "$lang_stats.miscellaneous.years_months_days" only_bottom_level_items = false } days = { label = "$lang_stats.miscellaneous.days" database_field_name = "date_time" } day_of_week = "" hour_of_day = "" } } # date_time_group } # report_groups } # create_profile_wizard_options } # autodesk_license_manager_enhanced