git-svn-id: http://svn.eurecom.fr/openair4G/trunk@7886 818b1a75-f10b-46b9-bf7c-635c3b92a50f
355 lines
14 KiB
Python
Executable File
355 lines
14 KiB
Python
Executable File
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
# Lionel GAUTHIER
|
|
# This script is a downgrade of a python script written for the openair stack, generating sequence diagrams charts, displaying
|
|
# messages exchanged between LTE access stratum protocol entities.
|
|
# This script needs mscgen tool (http://www.mcternan.me.uk/mscgen/).
|
|
#
|
|
# The aim of this script is to collect some traces from oaisim stack and generate a mscgen script, then generate a sequence diagram
|
|
# image (png or jpeg) based on the scripts generated.
|
|
# An example of how it can be invoqued: msc_gen.py /tmp/msc_log.txt /tmp/msc_log2.txt msc_logx.txt are input text files,
|
|
# They/It are/is generated by the execution of executables in linux user space. May be it is better to operate on log files 'grepped' with MSC:
|
|
# ./my_exe.exe | grep \[MSC > /tmp/msc_log1.txt
|
|
|
|
|
|
# Now, examples of how to generate a mscgen trace in a C executable:
|
|
# -First you have to declare the instance(s) of the protocol(s) that will send or receive messages.
|
|
# This is done with the following line:
|
|
# [MSC_NEW][system time][protocol_name=instance_name]
|
|
# examples:
|
|
# printf("[MSC_NEW][%s][MIH-F=%s]\n", getTimeStamp4Log(), g_mihf_id); for declaring a new instance of a protocol entity of type MIH-F
|
|
# with an instance name g_mihf_id (of type char*)
|
|
# printf("[MSC_NEW][%s][NAS=%s]\n", getTimeStamp4Log(), "nas"); other example.
|
|
# This declaration of instances of protocols is mandatory to for this script to work.
|
|
#
|
|
# -Then for tracing a message you have to log a line following this format:
|
|
# [MSC_MSG][system time][source instance_name][--- message_name --->][destination instance_name]
|
|
# Note:
|
|
# ---> means a message that has been received correctly by destination
|
|
# ---x means a message lost by destination
|
|
# example
|
|
# NOTICE("[MSC_MSG][%s][%s][--- Link_Register.indication\\n%s ---x][%s]\n",getTimeStamp4Log(),g_link_id,g_msc_gen_buf,g_mihf_id);
|
|
#
|
|
|
|
|
|
|
|
|
|
import sys
|
|
import subprocess
|
|
import re
|
|
import socket
|
|
import datetime
|
|
import os.path
|
|
from datetime import date
|
|
|
|
MSCGEN_OUTPUT_TYPE = "png"
|
|
MAX_MESSAGES_PER_PAGE = 36
|
|
|
|
SYSTEM_FRAME_NUMBER_STR = 'FRAME'
|
|
MODULE_STR = 'MOD'
|
|
RADIO_BEARER_STR = 'RB'
|
|
MSC_NEW_STR = '[MSC_NEW]'
|
|
MSC_MSG_STR = '[MSC_MSG]'
|
|
MSC_NBOX_STR = '[MSC_NBOX]'
|
|
MSC_BOX_STR = '[MSC_BOX]'
|
|
MSC_ABOX_STR = '[MSC_ABOX]'
|
|
MSC_RBOX_STR = '[MSC_RBOX]'
|
|
|
|
# This dic is filled as follow : g_entities_dic[protocol_instance_name].append(protocol_name)
|
|
# where protocol_name can be any of the following MI-USER, MIH-F, RAL, LINK-SAP
|
|
g_entities_dic = {}
|
|
g_reverse_entities_dic = {}
|
|
|
|
|
|
# g_messages is filled with dictionnaries:
|
|
# message_dic['entity_src'] = protocol_entity_src
|
|
# message_dic['entity_dst'] = protocol_entity_dest
|
|
# message_dic['msg'] = message
|
|
# message_dic['line_color'] = g_display_color[entity_name]
|
|
# message_dic['text_color'] = g_display_color[entity_name]
|
|
# message_dic['time'] = system_frame_number
|
|
# message_dic['seq_no'] = sequence_number_generator()
|
|
# g_messages.append(message_dic)
|
|
g_messages = []
|
|
g_messages_dic = {}
|
|
|
|
|
|
# g_display_order_dic is a dictionnary where the order of the display of entities sharing the same module identifier is hardcoded
|
|
#MAC and PHY valus have to be above num max radio bearer value
|
|
#g_display_order_dic = {'MIH-USER': 0, 'MIH-F': 1, 'RAL': 3, 'NAS': 4}
|
|
g_display_order_dic = {'NAS-UE': 0, 'AS': 1, 'NAS-MME': 3}
|
|
|
|
# Display color of messages of sending entities
|
|
g_display_color = {'IP': '\"teal\"',
|
|
'RRC_UE': '\"red\"',
|
|
'MIH-USER': '\"black\"',
|
|
'MIH-F': '\"black\"',
|
|
'RAL': '\"black\"',
|
|
'RAL_M': '\"black\"',
|
|
'RLC_UM': '\"navy\"',
|
|
'RLC_TM': '\"navy\"',
|
|
'NAS': '\"black\"',
|
|
'MAC_eNB': '\"indigo\"',
|
|
'PHY': '\"purple\"',
|
|
'NAS-UE': '\"black\"',
|
|
'NAS-MME': '\"black\"',
|
|
'AS': '\"black\"'}
|
|
|
|
|
|
g_final_display_order_list = []
|
|
g_sequence_generator = 0
|
|
|
|
def sequence_number_generator():
|
|
global g_sequence_generator
|
|
l_seq = g_sequence_generator
|
|
g_sequence_generator = g_sequence_generator + 1
|
|
return l_seq
|
|
|
|
def parse_log_file_for_discovering_protocol_entities(filename):
|
|
global g_entities_dic
|
|
global g_entities
|
|
global g_messages
|
|
global g_final_display_order_list
|
|
#open TXT file that contain OAI filtered traces for mscgen
|
|
|
|
fhandle = open(filename, 'r')
|
|
fcontent = fhandle.read()
|
|
fhandle.close()
|
|
|
|
# split file content in lines
|
|
lines = fcontent.splitlines()
|
|
for line in lines:
|
|
system_time = 'unknown'
|
|
|
|
# if line is a trace of the creation of a new protocol instance
|
|
if MSC_NEW_STR in line:
|
|
partition = line.rpartition(MSC_NEW_STR)
|
|
msc_log_string = partition[2]
|
|
#print (" %s " % msc_log_string)
|
|
partition = msc_log_string.split('[')
|
|
print ("\n\n %s \n" % partition)
|
|
#if len(partition) == 2:
|
|
|
|
item = partition[1]
|
|
item = item.strip()
|
|
item = item.strip(']')
|
|
system_time = item.split(' ')[-1]
|
|
print ("NEW system_time %s " % system_time)
|
|
|
|
item = partition[2]
|
|
item = item.strip()
|
|
item = item.strip(']')
|
|
protocol_entity_type = item.split('=')[0]
|
|
protocol_entity_name = item.split('=')[-1]
|
|
print ("NEW protocol_entity_type %s " % protocol_entity_type)
|
|
print ("NEW protocol_entity_name %s " % protocol_entity_name)
|
|
|
|
if protocol_entity_name not in g_entities_dic:
|
|
g_entities_dic[protocol_entity_name] = protocol_entity_type
|
|
|
|
if protocol_entity_type not in g_reverse_entities_dic:
|
|
g_reverse_entities_dic[protocol_entity_type] = protocol_entity_name
|
|
else:
|
|
entity_name_list = g_reverse_entities_dic[protocol_entity_type]
|
|
entity_name_list.append(protocol_entity_name)
|
|
g_reverse_entities_dic[protocol_entity_type] = entity_name_list
|
|
#print (" g_entities_dic[%d][%d].append(%s)" % (module_id_int, radio_bearer_id_int, entity_name_src))
|
|
print (" g_entities_dic= %s\n\n" % (g_entities_dic))
|
|
print (" g_reverse_entities_dic= %s\n\n" % (g_reverse_entities_dic))
|
|
|
|
#g_entities.append(protocol_entity_type)
|
|
#print (" %s \n" % protocol_entity)
|
|
|
|
|
|
|
|
|
|
|
|
def parse_log_file(filename):
|
|
global g_entities_dic
|
|
global g_entities
|
|
global g_messages
|
|
global g_final_display_order_list
|
|
#open TXT file that contain OAI filtered traces for mscgen
|
|
fhandle = open(filename, 'r')
|
|
fcontent = fhandle.read()
|
|
fhandle.close()
|
|
|
|
# split file content in lines
|
|
lines = fcontent.splitlines()
|
|
for line in lines:
|
|
system_time = 'unknown'
|
|
message = 'unknown'
|
|
entity_name_src = 'unknown'
|
|
entity_name_dest = 'unknown'
|
|
|
|
|
|
# if line is a trace of the creation of a new protocol instance
|
|
if MSC_MSG_STR in line:
|
|
partition = line.strip().rpartition(MSC_MSG_STR)
|
|
msc_log_string = partition[2].strip()
|
|
print (" ++++ %s " % msc_log_string)
|
|
partition = msc_log_string.split('[')
|
|
print (" ++++ %s " % partition)
|
|
|
|
#if len(partition) == 9:
|
|
message_dic = {}
|
|
|
|
system_time = partition[1].strip().split(' ')[-1].strip(']')
|
|
message_dic['display_time'] = system_time
|
|
seconds_int = int(system_time.split(':')[0])
|
|
micro_seconds_int = int(system_time.split(':')[-1])
|
|
system_time_int = seconds_int*1000000 + micro_seconds_int
|
|
system_time=str(system_time_int)
|
|
print ('system_time %s' % system_time)
|
|
|
|
entity_name_src = partition[2].strip().split(' ')[-1].strip(']')
|
|
print ('entity_name_src %s' % entity_name_src)
|
|
|
|
message = partition[3].strip().strip(']').strip()
|
|
if (message[-1] == 'x') or (message[-1] == 'X'):
|
|
message_dic['arc'] = '-x'
|
|
elif message[-1] == '>':
|
|
message_dic['arc'] = '=>'
|
|
message = message.strip('<').strip('>').strip('x').strip('X').strip('-').strip('=').strip()
|
|
print ('message %s' % message)
|
|
|
|
entity_name_dest = partition[4].strip().split(' ')[-1].strip(']')
|
|
print ('entity_name_dest %s' % entity_name_dest)
|
|
message_dic['entity_src'] = entity_name_src
|
|
message_dic['entity_dst'] = entity_name_dest
|
|
message_dic['msg'] = message
|
|
message_dic['line_color'] = g_display_color[g_entities_dic[entity_name_src]]
|
|
message_dic['text_color'] = g_display_color[g_entities_dic[entity_name_src]]
|
|
message_dic['time'] = system_time
|
|
#message_dic['seq_no'] = sequence_number_generator()
|
|
print ('%s\n\n' % message_dic)
|
|
g_messages_dic[system_time_int] = message_dic
|
|
#g_messages.append(message_dic)
|
|
|
|
#TODO !!!
|
|
if MSC_RBOX_STR in line:
|
|
partition = line.strip().rpartition(MSC_RBOX_STR)
|
|
msc_log_string = partition[2].strip()
|
|
print (" ==== %s " % msc_log_string)
|
|
partition = msc_log_string.split('[')
|
|
print (" ==== %s " % partition)
|
|
#TODO !!!
|
|
|
|
def generate_sorted_message_list():
|
|
first_time_stamp = 0
|
|
for system_time_int in sorted(g_messages_dic.iterkeys()):
|
|
if first_time_stamp == 0:
|
|
first_time_stamp = system_time_int
|
|
message_dic = g_messages_dic[system_time_int]
|
|
message_dic['seq_no'] = sequence_number_generator()
|
|
message_dic['display_time'] = str(system_time_int - first_time_stamp)
|
|
g_messages.append(message_dic)
|
|
|
|
def generate_sorted_entity_display_list():
|
|
module_display_order_dic = {}
|
|
for entity_name in sorted(g_entities_dic.iterkeys()):
|
|
module_display_order_dic[g_display_order_dic[g_entities_dic[entity_name]]] = entity_name
|
|
|
|
|
|
print("------------------------------------")
|
|
print(" %s " % (module_display_order_dic))
|
|
|
|
for display_priority in sorted(module_display_order_dic.iterkeys()):
|
|
g_final_display_order_list.append(module_display_order_dic[display_priority])
|
|
|
|
def msc_chart_write_header(fileP):
|
|
global g_final_display_order_list
|
|
fileP.write("msc {\n")
|
|
fileP.write("width = \"2048\";\n")
|
|
|
|
entity_line_list_str = ''
|
|
for entity in g_final_display_order_list:
|
|
entity_line_list_str = entity_line_list_str + ' ' + entity + ','
|
|
|
|
entity_line_list_str = entity_line_list_str.rstrip().strip(',')
|
|
fileP.write(" %s;" % (entity_line_list_str))
|
|
|
|
|
|
def msc_chart_write_footer(fileP):
|
|
fileP.write("\n}\n")
|
|
|
|
def msc_chart_generate(file_nameP):
|
|
global MSCGEN_OUTPUT_TYPE
|
|
command_line = "mscgen -T " + MSCGEN_OUTPUT_TYPE + " -i " + file_nameP + "; chmod 777 " +file_nameP + ";"
|
|
|
|
print("Command Line: %s " % (command_line))
|
|
fi,fo,fe=os.popen3(command_line)
|
|
for i in fe.readlines():
|
|
print "error:",i
|
|
|
|
def get_nem_file_descriptor():
|
|
global g_base_file_name
|
|
global g_page_index
|
|
l_file_name = g_base_file_name + str(g_page_index)+'.txt'
|
|
l_file = open(l_file_name, "w", 0777)
|
|
return l_file
|
|
|
|
|
|
###### MAIN START HERE #################
|
|
num_args = len(sys.argv)
|
|
if num_args < 2: # the program name and the arguments
|
|
# stop the program and print an error message
|
|
sys.exit("Must provide at least one file to parse")
|
|
|
|
for i in range(1,num_args):
|
|
print sys.argv[i]
|
|
|
|
for i in range(1,num_args):
|
|
parse_log_file_for_discovering_protocol_entities(sys.argv[i])
|
|
|
|
for i in range(1,num_args):
|
|
parse_log_file(sys.argv[i])
|
|
|
|
generate_sorted_message_list()
|
|
generate_sorted_entity_display_list()
|
|
|
|
g_page_index = 0
|
|
g_message_index = 0
|
|
g_message_index_in_current_page = 0
|
|
g_now = datetime.datetime.now()
|
|
g_now_formated = g_now.strftime("%Y-%m-%d_%H.%M.%S")
|
|
g_currentdir = os.curdir
|
|
g_resultdir = os.path.join(g_currentdir, g_now_formated)
|
|
os.mkdir(g_resultdir, 0777)
|
|
os.chdir(g_resultdir)
|
|
|
|
g_base_file_name = 'mih_mscgen_page_'
|
|
|
|
g_file = get_nem_file_descriptor()
|
|
msc_chart_write_header(g_file)
|
|
|
|
for message in g_messages:
|
|
|
|
if 'msg' in message:
|
|
print ('message %s' % message)
|
|
g_file.write(" %s%s%s [ label = \"(%d) T%s %s\", linecolour=%s , textcolour=%s ] ;\n" % (message['entity_src'], message['arc'], message['entity_dst'], message['seq_no'], message['display_time'], message['msg'], message['line_color'], message['text_color']))
|
|
elif 'box' in message:
|
|
g_file.write(" %s %s %s [ label = \"%s\", textbgcolour=%s , textcolour=%s ] ;\n" % (message['entity_src'], message['box_type'], message['entity_dst'], message['box'], message['textbg_color'], message['text_color']))
|
|
|
|
g_message_index = g_message_index + 1
|
|
g_message_index_in_current_page = g_message_index_in_current_page + 1
|
|
|
|
if (g_message_index_in_current_page == MAX_MESSAGES_PER_PAGE):
|
|
msc_chart_write_footer(g_file)
|
|
g_file.close()
|
|
msc_chart_generate(g_file.name)
|
|
g_page_index = g_page_index + 1
|
|
g_message_index_in_current_page = 0
|
|
|
|
g_file = get_nem_file_descriptor()
|
|
msc_chart_write_header(g_file)
|
|
|
|
|
|
msc_chart_write_footer(g_file)
|
|
g_file.close()
|
|
if g_message_index_in_current_page >= 1:
|
|
msc_chart_generate(g_file.name)
|
|
else:
|
|
print("Removing empty seq diagram file: %s " % (g_file.name))
|
|
os.remove(g_file.name)
|