# Copyright (c) 2014 Flowerfire, Inc. All Rights Reserved. evostream = { plugin_version = "1.0.1" info.1.manufacturer = "Evostream" info.1.device = "Media Server" info.1.version.1 = "1.6.5" # 3003 # 2014-03-18 - GMF - 1.0 - Initial creation # 2014-03-28 - GMF - 1.0.1 - Added support for spaces in field names in #Fields header # The name of the log format log.format.format_label = "Evostream Media Server Log Format" log.miscellaneous.log_data_type = "generic_w3c" log.miscellaneous.log_format_type = "media_server" # The log is in this format if any of the first ten lines match this regular expression ##Software: Evostream Media Server 1.6.5 3003 log.format.autodetect_regular_expression = "^#Software: Evostream Media Server" log.format.field_separator = " " # This handles #Fields lines, and creates log and database fields from them log.filter_preprocessor = ` if (matches_regular_expression(current_log_line(), '^#Fields: +([^ ].*)$')) then ( string fields = $1; string fieldname; v.logfieldindex = 1; string numerical_fields = "profiles." . internal.profile_name . ".database.numerical_fields"; # Send this line to all parsing servers distribute_format_line(current_log_line()); # Reset all log fields to 0/0 so none carry over from the previous format line definition node log_fields = "profiles"{internal.profile_name}{"log"}{"fields"}; node log_field; foreach log_field log_fields ( @log_field{"index"} = 0; @log_field{"subindex"} = 0; ); # This subroutine creates a database field subroutine(create_database_field(string fieldname, int top, int bottom), ( #echo("create_database_field: " . fieldname); # debug debug_message("create_database_field(" . fieldname . ")\n"); string databasefieldpath = "profiles." . internal.profile_name . ".database.fields." . fieldname; (databasefieldpath . "") = ""; node databasefield = databasefieldpath; if (top ne 0) then set_subnode_value(databasefield, "suppress_top", top); if (bottom ne 0) then set_subnode_value(databasefield, "suppress_bottom", bottom); databasefield; )); subroutine(create_log_field(string fieldname, string log_field_type, bool withindex), ( debug_message("create_log_field(" . fieldname . "; log_field_type=" . log_field_type . ")\n"); # echo("create_log_field(" . fieldname . "; log_field_type=" . log_field_type . ")"); string logfieldpath = "profiles." . internal.profile_name . ".log.fields." . fieldname; (logfieldpath . "") = ""; node logfield = logfieldpath; if (withindex) then ( set_subnode_value(logfield, "index", v.logfieldindex); v.logfieldindex++; ); set_subnode_value(logfield, "subindex", 0); if (log_field_type ne '') then set_subnode_value(logfield, "log_field_type", log_field_type); logfield; )); # Assume there isn't a localtime field until we see one. v.parse_localtime = false; # Get the log format separator. Assume at least two fields. # 2010-02-01 - GMF - Changed the default from " " to "" (any whitespace). With " " as the default, data which # has a spaces in the header, but tabs in the data, doesn't parse, because this assumes space # separators. Truly generic W3C header parsing appears to be impossible, which is why we can do # per-plugin parsing now; but that's just moved the problem here, where we'll still have to # fight it forever. Hopefully, "" gives better coverage to the universe of W3C variants than " ". # log.format.field_separator = " "; log.format.field_separator = ""; if (matches_regular_expression(fields, '^[^ ]+ [^ ]+')) then ( log.format.field_separator = " "; ); # Extract the fields on at a time while (matches_regular_expression(fields, '^([^ ]+)[ ](.*)$') or matches_regular_expression(fields, '^([^ ]+)$')) ( string unconverted_fieldname = $1; fields = $2; # Clean up the field name fieldname = ''; for (int i = 0; i < length(unconverted_fieldname); i++) ( string c = lowercase(substr(unconverted_fieldname, i, 1)); if (!matches_regular_expression(c, '^[a-z0-9]$')) then c = '_'; fieldname .= c; ); while (matches_regular_expression(fieldname, '^(.*)_$')) fieldname = $1; # Get the log field type string log_field_type = 'flat'; # if (fieldname eq 'cs_referrer') then ( # fieldname = 'cs_referer'; # ); # if (fieldname eq 'cs_uri') then ( # fieldname = 'cs_uri_stem'; # ); # 2013-12-23 - GMF - Don't make cs_referrer type "referrer" anymore; we now do all referrer derivation in snapons, and this will create duplicate fields. # if (fieldname eq 'cs_referer') then ( # log_field_type = 'url'; # ); # 2013-12-23 - GMF - Don't make cs_uri_stem type "page" anymore; we now have a snapon computing screen dimensions, and if we make this type page, it will override cs_uri_stem with "(screen info)" and then screen info from the snapon won't be computed. # else if (fieldname eq 'cs_uri_stem') then ( # log_field_type = 'page'; # ); # 2013-12-23 - GMF - Don't make cs_referrer type "agent" anymore; we now do all agent derivation in snapons, and this will create duplicate fields. # else if (fieldname eq 'cs_user_agent') then ( # log_field_type = 'agent'; # ); # 2013-12-23 - GMF - Don't make c_ip type "host" anymore; we now do all agent derivation in snapons, and this will create duplicate fields. # else if (fieldname eq 'c_ip') then ( # log_field_type = 'host'; # ); # Create the log field # 2013-05-15 - GMF - We need to create these sc_bytes and cs_bytes log fields here, because otherwise web_server_package won't create the database fields. Why were they excluded? Maybe when this was copied from another plug-in which computes them from another field? # if ((fieldname ne "sc_bytes") and (fieldname ne "cs_bytes")) then create_log_field(fieldname, log_field_type, true); # if (fieldname eq "localtime") then # v.parse_localtime = true; # If we're creating a profile, create the database fields too. if (node_exists("volatile.creating_profile")) then ( if (false) then ( ) # Handle localtime by creating date_time and derived database fields # if (fieldname eq "localtime") then ( # create_log_field('date', '', false); # create_log_field('time', '', false); # create_database_field('date_time', 0, 0); # create_database_field('day_of_week', 0, 0); # create_database_field('hour_of_day', 0, 0); # ); # if localtime # Don't track these fields in the database # if ((fieldname eq "sc_bytes") or (fieldname eq "cs_bytes") or (fieldname eq 'cs_uri_query') or (fieldname eq 'cs_cookie')) then # ( ); # Don't track these fields in the database else if ((fieldname eq "timestamp") or (fieldname eq 'querytimestamp') or (fieldname eq 'creationtimestamp')) then ( ); # Handle date by creating date_time and derived database fields # else if (fieldname eq "date") then ( # create_log_field('localtime', '', false); # placeholder - 7/Nov/2006 - KBB # create_database_field('date_time', 0, 0); # create_database_field('day_of_week', 0, 0); # create_database_field('hour_of_day', 0, 0); # ); # if date # else if (fieldname eq "time") then ( # create_database_field('date_time', 0, 0); # create_database_field('day_of_week', 0, 0); # create_database_field('hour_of_day', 0, 0); # ); # if time # Create derived fields for agent # else if (fieldname eq "cs_user_agent") then ( # create_database_field('operating_system', 0, 0); # create_database_field('web_browser', 0, 0); # create_database_field('spider', 0, 0); # ); # Create database field cs_ip and derived field for client IP # else if (fieldname eq "c_ip") then ( # create_database_field('c_ip', 0, 0); # create_database_field('location', 0, 0); # ); # Create database field cs_referer and derived fields for referrer # else if (fieldname eq "cs_referer") then ( # create_database_field('cs_referer', 1, 9); # create_database_field('search_engine', 0, 0); # create_database_field('search_phrase', 0, 0); # ); # Create derived file type field # else if (fieldname eq "cs_uri_stem") then ( # create_database_field('cs_uri_stem', 0, 9); # 2013-12-23 - GMF - Don't file_type anymore; this is done with a snapon now # create_database_field('file_type', 0, 0); # ); # Don't add a database field for numerical fields else if (subnode_exists(numerical_fields, fieldname)) then ( debug_message("Not adding numerical field: " . fieldname . "\n"); ); # Create a normal database field else create_database_field(fieldname, 0, 0); ); # if creating profile ); # while another field # Don't parse the #Fields line as a data line 'reject'; ); # if #Fields # Don't parse any other # lines as data lines else if (starts_with(current_log_line(), '#')) then ( 'reject'; ); ` log.fields = { # timestamp = "" # info = "" # name = "" # applicationname = "" # creationtimestamp = "" # type = "" # typenumeric = "" # uniqueid = "" # uptime = "" # querytimestamp = "" # bandwidth = "" # connectiontype = "" # farip = "" # farport = "" # ip = "" # nearip = "" # nearport = "" # port = "" # audio codec = "" # audio_codecnumeric = "" # audio_bytes = "" # audio_droppedbytes = "" # audio_packets = "" # audio_droppedpackets = "" # video_bytes = "" # video_codec = "" # video_codecnumeric = "" # video_droppedbytes = "" # video_droppedpackets = "" # video_packets = "" # pullsettings_audiocodecbytes = "" # pullsettings_configid = "" # pullsettings_emulateuseragent = "" # pullsettings_forcetcp = "" # pullsettings_httpproxy = "" # pullsettings_isaudio = "" # pullsettings_keepalive = "" # pullsettings_localstreamname = "" # pullsettings_operationtype = "" # pullsettings_pageurl = "" # pullsettings_ppsbytes = "" # pullsettings_rangeend = "" # pullsettings_rangestart = "" # pullsettings_rtcpdetectioninterval = "" # pullsettings_sendrenewstream = "" # pullsettings_spsbytes = "" # pullsettings_ssmip = "" # pullsettings_swfurl = "" # pullsettings_tcurl = "" # pullsettings_tos = "" # pullsettings_ttl = "" # pullsettings_uri = "" # recordsettings_chunklength = "" # recordsettings_computedpathtofile = "" # recordsettings_configid = "" # recordsettings_keepalive = "" # recordsettings_localstreamname = "" # recordsettings_mp4binpath = "" # recordsettings_operationtype = "" # recordsettings_overwrite = "" # recordsettings_pathtofile = "" # recordsettings_type = "" # recordsettings_waitforidr = "" # recordsettings_winqtcompat = "" date = "" time = "" events = "" } # log.fields log.parsing_filters.parse_timestamp = ` if (matches_regular_expression(timestamp, '^([^ ]+) (.*)$')) then ( date = normalize_date($1, "auto"); time = normalize_time($2, "auto"); # date_time = date . " " . time; ); #date = normalize_date(creationtimestamp / 1000, 'seconds_since_jan1_1970'); #time = normalize_time(creationtimestamp / 1000, 'seconds_since_jan1_1970'); ` 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.fields.location = "" database.fields = { date_time = "" day_of_week = "" hour_of_day = "" } # database.fields database.numerical_fields = { events = { default = true requires_log_field = false } # events audio_bytes = { default = true integer_bytes = 64 display_format_type = "bandwidth" } # audio_bytes audio_droppedbytes = { integer_bytes = 64 display_format_type = "bandwidth" } # audio_droppedbytes audio_packets = "" audio_droppedpackets = "" video_bytes = { default = true integer_bytes = 64 display_format_type = "bandwidth" } # video_bytes video_droppedbytes = { integer_bytes = 64 display_format_type = "bandwidth" } # video_dropped_bytes video_packets = "" video_droppedpackets = "" pullsettings_audiocodecbytes = { integer_bytes = 64 display_format_type = "bandwidth" } # pullsettings_audiocodecbytes pullsettings_ppsbytes = { integer_bytes = 64 display_format_type = "bandwidth" } # pullsettings_ppsbytes pullsettings_pspbytes = { integer_bytes = 64 display_format_type = "bandwidth" } # pullsettings_pspbytes } # database.numerical_fields create_profile_wizard_options = { # How the reports should be grouped in the report menu report_groups = { date_time_group = "" recordsettings_group = { recordsettings_chunklength = true recordsettings_computedpathtofile = true recordsettings_configid = true recordsettings_keepalive = true recordsettings_localstreamname = true recordsettings_mp4binpath = true recordsettings_operationtype = true recordsettings_overwrite = true recordsettings_pathtofile = true recordsettings_type = true recordsettings_waitforidr = true recordsettings_winqtcompat = true } # recordsettings_group pullsettings_group = { pullsettings_audiocodecbytes = true pullsettings_configid = true pullsettings_emulateuseragent = true pullsettings_forcetcp = true pullsettings_httpproxy = true pullsettings_isaudio = true pullsettings_keepalive = true pullsettings_localstreamname = true pullsettings_operationtype = true pullsettings_pageurl = true pullsettings_ppsbytes = true pullsettings_rangeend = true pullsettings_rangestart = true pullsettings_rtcpdetectioninterval = true pullsettings_sendrenewstream = true pullsettings_spsbytes = true pullsettings_ssmip = true pullsettings_swfurl = true pullsettings_tcurl = true pullsettings_tos = true pullsettings_ttl = true pullsettings_uri = true } # pullsettings_group } # report_groups # snapons = { # # # Attach a media_reports snapon # media_reports = { # snapon = "media_reports" # name = "media_reports" # label = "$lang_admin.snapons.media_reports.label" # parameters = { # user_field.parameter_value = "c_ip" ## have_category_field.parameter_value = false ## category_field.parameter_value = "category" ## domain_field.parameter_value = "top_level_domain" # duration_field.parameter_value = "play_duration" # stream_name_field.parameter_value = "x_sname" # stream_id_field.parameter_value = "x_stream_id" # client_ip_field.parameter_value = "ip" # # # Don't do the default concurrent connections analysis; Wowza has its own, better one (concurrent_streams_wowza, below) # attach_concurrent_events.parameter_value = false # # } # parameters # # } # media_reports # Attach the referrer_analysis snapon # referrer_analysis = { # snapon = "referrer_analysis" # name = "referrer_analysis" # label = "$lang_admin.snapons.referrer_analysis.label" # prompt_to_attach = true # prompt_to_attach_default = false # parameters = { # referrer_field.parameter_value = "c_referrer" # } # parameters # requires_database_fields = { # c_referrer = true # } # requires_database_fields # } # referrer_analysis # } # snapons } # create_profile_wizard_options } # evostream