- •Модели управления риском в it-архитектуре
- •Задание на выполнение выпускной квалификационной работы
- •Реферат
- •Содержание
- •Введение
- •1. Теоретические основы управления рисками в ит-архитектурах
- •1.1. Определение понятия рисков и их влияния на ит-архитектурах
- •1.2. Классификация и типология рисков в ит-архитектурах
- •1.3. Обзор методов и математических моделей для управления рисков в ит-архитектурах
- •1.4. Анализ существующих решений и их ограничений для управления рисками в ит-архитектурах
- •Выводы по главе
- •2. Разработка программного инструмента для автоматизированного анализа рисков
- •2.1. Постановка задачи и определение целевой аудитории
- •2.2. Выбор технологий и инструментов
- •2.3. Разработка алгоритмов анализа рисков
- •2.4. Реализация программного инструмента
- •2.5. Тестирование и оценка эффективности решения
- •Выводы по главе
- •Заключение
- •Список использованных источников
- •Приложение
Приложение
# Анализатор логов
#
import gzip
from collections import namedtuple
from analyzer import Analyzer
import argparse
import json
import os
import sys
import logging
from string import Template
import re
from datetime import date
config = {
'REPORT_SIZE': 1000,
'REPORT_DIR': './reports',
'LOG_DIR': './log',
'ERROR_PERC': 50.0,
# 'LOG': 'loganalyzer.log',
}
filename_pattern = re.compile(
r'^nginx-access-ui.log-'
r'(?P<year>\d{4})'
r'(?P<month>\d{2})'
r'(?P<day>\d{2})'
r'(?=(?P<ext>.gz){0,1}$)'
)
line_pattern = re.compile(
r'"(?P<request>(?P<method>GET|POST)\s(?P<url>[\w\d\S]+)\s([\w\d\S]+))"'
r'[\s\S]+'
r'(?P<request_time>\d.\d{3}$)'
)
report_template = './report.html'
Log = namedtuple('Log', ['path', 'date', 'ext'])
# Получение и обработка аргументов командной строки
def get_cmd_argument(cmd_args):
"""Возвращает объект Namespace с аргументами командной строки."""
args_parser = argparse.ArgumentParser()
args_parser.add_argument(
'--config',
help='Задать другой конфигурационный файл',
)
return args_parser.parse_args(cmd_args)
def parse_file_config(user_config):
"""Парсит заданный пользовательем конфигурационный файл."""
if user_config is not None:
file_config = {}
with open(user_config, 'r') as f:
try:
for line in f:
attrs = line.split('=')
if attrs[1].rstrip().isnumeric():
file_config[attrs[0]] = int(attrs[1].rstrip())
else:
file_config[attrs[0]] = attrs[1].rstrip()
except IndexError:
file_config = {}
return file_config
def get_config(config):
"""Возвращает итоговый конфиг.
Происходит парсинг аргументов команодной строки.
Cлияние конфигов. В итоговый конфиг включается поле LOG данного скрипта(loganalyzer)"""
args = get_cmd_argument(sys.argv[1:])
config_file = parse_file_config(args.config)
if config_file is None:
config_file = {}
config.update(config_file)
if 'LOG' not in config.keys():
config['LOG'] = None
return config
def write_report(
template_file,
report_file,
data,
report_size,
):
"""Запись REPORT_SIZE строк в файл отчета."""
with open(template_file, 'r') as file:
template = Template(file.read())
with open(report_file, 'wb') as report:
report.write(template.safe_substitute(table_json=json.dumps(data[:report_size])).encode(encoding='utf-8'))
def get_report_file_path(report_dir, log_date):
"""Формирует имя файла отчета и путь до него по имени анализируемого лога."""
filename = 'report-{}.html'.format(log_date.strftime('%Y.%m.%d'))
report_file_path = os.path.join(report_dir, filename)
return report_file_path
def get_date(match):
if match is None:
return None
return date.fromisoformat('{}-{}-{}'.format(
match.group('year'),
match.group('month'),
match.group('day'),
)
)
def get_log(log_dir, regexp=filename_pattern):
"""Поиск файла лога."""
latest_date = date(1, 1, 1)
log = Log(None, None, None)
for path, _, files in os.walk(log_dir, topdown=True):
for f in files:
match = regexp.search(f)
log_date = get_date(match)
if match and log_date > latest_date:
latest_date = log_date
log = Log(
os.path.join(path, f),
latest_date,
match.group('ext'),
)
continue
else:
continue
return log
def parse_log(log, regexp=line_pattern):
if log.ext == '.gz':
f = gzip.open(log.path, 'rb')
else:
f = open(log.path, 'rb')
for line in f:
try:
match = regexp.search(
line.decode('utf-8')
)
yield match.group('url'), match.group('request_time')
except AttributeError:
yield '-', '0.0'
f.close()
def main(config):
log = get_log(config['LOG_DIR'])
if log.path is None:
sys.exit(0)
report_file = get_report_file_path(
config['REPORT_DIR'],
log.date,
)
# Если файл отчета существет, то происходит выход из программы.
if os.path.isfile(report_file):
logging.info('Отчет для последнего лога существует: {}'.format(report_file))
sys.exit(0)
logging.info('Отчет будет сохранен в файл: {}'.format(report_file))
parser = parse_log(log) # generator
analyzer = Analyzer()
# Для каждой строки лога парсер отдает url, time_request
logging.info('Производится предварительный анализ')
for url, time_request in parser:
# Формируется предварительный результат для каждого url:
# {
# 'url1': {'count':xx, 'time_sum':xx, 'set_times':xxx},
# }
try:
analyzer.get_temp_result(url, time_request)
except KeyboardInterrupt as e:
logging.exception(e)
# Проверка процента ошибок
if analyzer.errors_perc >= config['ERROR_PERC']:
logging.error('Превышен порог ошибок')
sys.exit(0)
logging.info('Порог ошибок {}%'.format(analyzer.errors_perc))
logging.info('Формируется итоговый результат')
report = analyzer.get_final_result()
logging.info('Запись отчета в файл: {}'.format(report_file))
write_report(
report_template,
report_file,
report,
config['REPORT_SIZE'],
)
sys.exit(0)
if __name__ == "__main__":
# Получение итогового конфига
try:
config = get_config(config)
except FileNotFoundError as e:
logging.exception(e)
# Конфигурирование логгера.
# Если лог скрипта не указан, то config['LOG'] = None
# Лог будет выводится в stdout.
# При указаном логе происходить запись в файл config['LOG'].
logging.basicConfig(
filename=config['LOG'],
filemode='a',
level=logging.INFO,
format='[%(asctime)s] %(levelname).1s %(message)s',
)
try:
main(config)
except Exception as e:
logging.exception(e)
def round_decorate(func):
def rounder(*args):
result = func(*args)
return round(result, 3)
return rounder
class Analyzer:
def __init__(self):
self.result = []
self._temp_result = {}
self._count_requests = 0
self._time_requests = 0.0
self._errors = 0
self.errors_perc = 0.0
def _count_errors_perc(self):
perc = self._errors * 100 / self._count_requests
return round(perc, 2)
def get_temp_result(self, url, request_time):
self._count_requests += 1
self._time_requests += float(request_time)
if url == '-' and request_time == '0.0':
self._errors += 1
self.errors_perc = self._count_errors_perc()
if url in self._temp_result.keys():
self._temp_result[url]['count'] += 1
self._temp_result[url]['time_sum'] += float(request_time)
self._temp_result[url]['set_times_url'].add(float(request_time))
else:
self._temp_result[url] = {
'count': 1,
'time_sum': float(request_time),
'set_times_url': {float(request_time)},
}
@round_decorate
def count_perc(self, url):
count = self._temp_result[url]['count']
percents = count * 100 / self._count_requests
return percents
@round_decorate
def time_perc(self, url):
time_sum = self._temp_result[url]['time_sum']
percents = time_sum * 100 / self._time_requests
return percents
@round_decorate
def time_avg(self, url):
count = self._temp_result[url]['count']
time_sum = self._temp_result[url]['time_sum']
return time_sum / count
@round_decorate
def time_med(self, url):
list_times = list(self._temp_result[url]['set_times_url'])
list_times.sort()
index = len(list_times) // 2
if len(list_times) % 2 != 0:
return list_times[index]
return sum(list_times[index - 1:index + 1]) / 2
def get_final_result(self):
for url in self._temp_result:
self.result.append(
{
'url': url,
'count': self._temp_result[url]['count'],
'count_perc': self.count_perc(url),
'time_sum': round(self._temp_result[url]['time_sum'], 3),
'time_perc': self.time_perc(url),
'time_avg': self.time_avg(url),
'time_max': max(self._temp_result[url]['set_times_url']),
'time_med': self.time_med(url),
}
)
self.result = sorted(
self.result,
reverse=True,
key=lambda d: d['time_sum'],
)
return self.result
1 Или директор высшей школы (на усмотрение структурного подразделения).
2 Указывается именно «Выпускная квалификационная работа» (см. п.2.5 ФГОС 3++; п.6.17 СУОС СПбПУ).
3 Консультант(ы) – при необходимости (по решению руководителя ОП или директора высшей школы).
