# Copyright (c) 2010 Flowerfire, Inc. All Rights Reserved. shoutcast18 = { plugin_version = "2.0" info.1.manufacturer = "Nullsoft" info.1.device = "SHOUTcast Media Server / DNAS (Distributed Network Audio Server)" info.1.version.1 = "1.6" info.1.version.2 = "1.8" info.1.version.3 = "1.9" info.1.version.4 = "2" # 01/Jun/2006 - GMF - 1.1 - cleaned up to remove defaults; changed "country" to "location" # 03/Feb/2009 - gas - 1.2 - modified the parsing regex, v8 complained about the regex # 2010-10-05 - 1.3 - MSG - Edited info lines. # 2010-10-14 - 1.4 - KBB - Changed from parsing regular expression to parsing filter to be able to make sure # the line contains "connection closed" before applying the regular expression. This is to help performance. # 2010-11-09 - 1.5 - KBB - Moved support for shoutcast 1.6 to this plug-in and added player field to retrive # that info from 1.9 logs. No longer checking for "connection closed" before applying regular expressions, # since the player info comes from a different line. Changed field names: hostname => dest and # unique_source_ips => unique_destinations. Used dest and userid as the key to associate the player # with the info on the "connection closed" line. This version has been tested with 1.6 and 1.9 logs. # 2012-05-08 - 2.0 - GMF - Added support for v2 format # The name of the log format log.format.format_label = "SHOUTcast Log Format" log.miscellaneous.log_data_type = "generic" log.miscellaneous.log_format_type = "media_server" # The log is in this format if any of the first ten lines match this regular expression #2012-04-20 16:25:14 I msg:[DST 12.34.56.78:50560 sid=1] SHOUTcast 1 client connection accepted. iTunes/10.5.3 (Macintosh; Intel Mac OS X 10.5.8) AppleWebKit/534.50.2 log.format.autodetect_regular_expression = "SHOUTcast.*v1.[689].*starting up|SHOUTcast [0-9]+ client connection accepted" # This regular expression is used to parse the log fields out of the log entry # log.format.parsing_regular_expression = "^<([0-9][0-9]/[0-9][0-9]/[0-9][0-9])@([0-9][0-9]:[0-9][0-9]:[0-9][0-9])> .dest: ([0-9.]*). connection closed \\(([0-9]*) seconds\\) \\(UID: ([0-9]*)\\)\\[L: [0-9]*\\].Bytes: ([0-9]*)" # log.format.parsing_regular_expression = "^<([0-9][0-9]/[0-9][0-9]/[0-9][0-9])@([0-9][0-9]:[0-9][0-9]:[0-9][0-9])> .dest: ([0-9.]*). connection closed .([0-9]*) seconds. .UID: ([0-9]*)..L: [0-9]*..Bytes: ([0-9]*)..P: [0-9]+." log.format.parse_only_with_filters = "true" # The format of dates and times in this log # log.format.date_format = "mm/dd/yy" # log.format.time_format = "h:mm:ss" # Log fields log.fields = { date = "" time = "" dest.type = "host" duration = "" user_id = "" bytes_transferred = "" player = "" } # log.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 log.parsing_filters.parse = ` v.line = current_log_line(); # Typically we get the date and time and other common elements first, but since so many lines are ignored, # it is more efficient not to get them when we don't need them. if (matches_regular_expression(v.line, "^<([0-9][0-9]/[0-9][0-9]/[0-9][0-9])@([0-9][0-9]:[0-9][0-9]:[0-9][0-9])> .dest: ([0-9.]*). connection closed .([0-9]*) seconds. .UID: ([0-9]*)..L: [0-9]*..Bytes: ([0-9]*)..P: [0-9]+.")) then ( v.key = $3 . "_" . $5; set_collected_field(v.key, 'date', normalize_date($1, 'mm/dd/yy')); set_collected_field(v.key, 'time', $2); set_collected_field(v.key, 'dest', $3); set_collected_field(v.key, 'duration', $4); set_collected_field(v.key, 'user_id', $5); set_collected_field(v.key, 'bytes_transferred', $6); accept_collected_entry(v.key, false); ); #2012-04-20 16:25:16 I msg:[DST 12.34.56.78:50560 sid=1] SHOUTcast 1 client connection closed (2 seconds) [Bytes: 285285] Agent: {BACKTICK}iTunes/10.5.3 (Macintosh; Intel Mac OS X 10.5.8) AppleWebKit/534.50.2' else if (matches_regular_expression(v.line, "^([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]) ([0-9][0-9]:[0-9][0-9]:[0-9][0-9]) [^ ]+ msg:[[]DST ([^ ]+) sid=[0-9]+[]] SHOUTcast [0-9]+ client connection closed [(]([0-9]+) seconds[)] [[]Bytes: ([0-9]+)[]] Agent: .([^']*)'")) then ( v.key = $3 . "_"; set_collected_field(v.key, 'date', $1); set_collected_field(v.key, 'time', $2); set_collected_field(v.key, 'dest', $3); set_collected_field(v.key, 'duration', $4); set_collected_field(v.key, 'bytes_transferred', $5); accept_collected_entry(v.key, false); ); else if (matches_regular_expression(v.line, "^<([0-9][0-9]/[0-9][0-9]/[0-9][0-9])@([0-9][0-9]:[0-9][0-9]:[0-9][0-9])> .dest: ([0-9.]*). connection closed .sent ([0-9]*) ")) then ( set_collected_field('', 'date', normalize_date($1, 'mm/dd/yy')); set_collected_field('', 'time', $2); set_collected_field('', 'dest', $3); set_collected_field('', 'bytes_transferred', $4); accept_collected_entry('', false); ); #<11/01/10@15:30:20> [dest: 64.12.243.204] starting stream (UID: 0)[L: 1]{A: SHOUTcast Directory Tester}(P: 0) else if (matches_regular_expression(v.line, "^<([0-9][0-9]/[0-9][0-9]/[0-9][0-9])@([0-9][0-9]:[0-9][0-9]:[0-9][0-9])> .dest: ([0-9.]*). starting stream .UID: ([0-9]*)..L: [0-9]*.\\\\{A: ([^}]+)\\\\}.P: [0-9]*.")) then ( v.key = $3 . "_" . $4; set_collected_field(v.key, 'date', normalize_date($1, 'mm/dd/yy')); set_collected_field(v.key, 'time', $2); set_collected_field(v.key, 'dest', $3); set_collected_field(v.key, 'user_id', $4); set_collected_field(v.key, 'player', replace_all(convert_escapes($5), '+', ' ')); # this is often encoded ); ` # Database fields database.fields = { date_time = "" day_of_week = "" hour_of_day = "" dest = "" domain_description = "" user_id = "" location = "" player = "" } # database.fields database.numerical_fields = { events = { default = true requires_log_field = false entries_field = true } # events unique_destinations = { log_field = "dest" type = "unique" } # unique_destinations duration = { type = "int" integer_bits = 64 display_format_type = "duration_compact" } # duration bytes_transferred = { type = "int" integer_bits = 64 display_format_type = "bandwidth" } # bytes_transferred } # database.numerical_fields create_profile_wizard_options = { # How the reports should be grouped in the report menu report_groups = { date_time_group = "" } # report_groups } # create_profile_wizard_options } # shoutcast18