|
9 | 9 | import click
|
10 | 10 | import warnings
|
11 | 11 | from typing import Any
|
| 12 | +import re |
12 | 13 |
|
13 | 14 | warnings.filterwarnings("ignore")
|
14 | 15 | from csle_common.dao.simulation_config.simulation_env_config import SimulationEnvConfig
|
@@ -3204,15 +3205,16 @@ def ls_shell_complete(ctx, param, incomplete) -> List[str]:
|
3204 | 3205 | "| node_exporter | cadvisor | pgadmin | statsmanager | flask | "
|
3205 | 3206 | "simulations | emulation_executions | cluster | nginx | postgresql | docker | hostmanagers | "
|
3206 | 3207 | "clientmanager | snortmanagers | elkmanager | trafficmanagers | kafkamanager | "
|
3207 |
| - "ossecmanagers | ryumanager | filebeats | metricbeats | heartbeats") |
| 3208 | + "ossecmanagers | ryumanager | filebeats | metricbeats | heartbeats | logfiles | logfile") |
3208 | 3209 | @click.argument('entity', default='all', type=str, shell_complete=ls_shell_complete)
|
3209 | 3210 | @click.option('--all', is_flag=True, help='list all')
|
3210 | 3211 | @click.option('--running', is_flag=True, help='list running only (default)')
|
3211 | 3212 | @click.option('--stopped', is_flag=True, help='list stopped only')
|
3212 | 3213 | @click.option('--ip', default="", type=str)
|
3213 | 3214 | @click.option('--id', default=None, type=int)
|
3214 | 3215 | @click.option('--name', default="", type=str)
|
3215 |
| -def ls(entity: str, all: bool, running: bool, stopped: bool, ip: str, name: str, id: int) -> None: |
| 3216 | +@click.option('--logfile_name', default="", type=str, help='name of the logfile to to retrieve') |
| 3217 | +def ls(entity: str, all: bool, running: bool, stopped: bool, ip: str, name: str, id: int, logfile_name: str) -> None: |
3216 | 3218 | """
|
3217 | 3219 | Lists the set of containers, networks, images, or emulations, or all
|
3218 | 3220 |
|
@@ -3293,6 +3295,10 @@ def ls(entity: str, all: bool, running: bool, stopped: bool, ip: str, name: str,
|
3293 | 3295 | list_heartbeats(ip=ip, emulation=name, ip_first_octet=id)
|
3294 | 3296 | elif entity == "packetbeats":
|
3295 | 3297 | list_packetbeats(ip=ip, emulation=name, ip_first_octet=id)
|
| 3298 | + elif entity == "logfiles": |
| 3299 | + list_logfiles(ip=ip) |
| 3300 | + elif entity == "logfile": |
| 3301 | + list_logfile(ip=ip, logfile_name=logfile_name) |
3296 | 3302 | else:
|
3297 | 3303 | container = get_running_container(name=entity)
|
3298 | 3304 | if container is not None:
|
@@ -3327,6 +3333,122 @@ def ls(entity: str, all: bool, running: bool, stopped: bool, ip: str, name: str,
|
3327 | 3333 | click.secho(f"entity: {entity} is not recognized", fg="red", bold=True)
|
3328 | 3334 |
|
3329 | 3335 |
|
| 3336 | +def list_logfiles(ip: str) -> None: |
| 3337 | + """ |
| 3338 | + Utility function for listing logfiles |
| 3339 | +
|
| 3340 | + :param ip: the ip of the node to list logfiles |
| 3341 | +
|
| 3342 | + :return: None |
| 3343 | + """ |
| 3344 | + import csle_common.constants.constants as constants |
| 3345 | + from csle_common.metastore.metastore_facade import MetastoreFacade |
| 3346 | + config = MetastoreFacade.get_config(id=1) |
| 3347 | + for node in config.cluster_config.cluster_nodes: |
| 3348 | + if node.ip == ip or ip == "": |
| 3349 | + logfiles_info = ClusterController.get_csle_log_files( |
| 3350 | + ip=ip, port=constants.GRPC_SERVERS.CLUSTER_MANAGER_PORT) |
| 3351 | + click.secho('+' + '-' * 60 + '+', fg='white') |
| 3352 | + click.secho(f'|{"CSLE log files":^20}|{"Directory":^39}|', fg='white') |
| 3353 | + click.secho('+' + '=' * 60 + '+', fg='white') |
| 3354 | + for key, value in logfiles_info.items(): |
| 3355 | + click.secho('|', nl=False, fg='white') |
| 3356 | + click.secho(f'{key:^20}', nl=False, fg='white') |
| 3357 | + click.secho('|', nl=False, fg='white') |
| 3358 | + click.secho(f'{value[0]:^39}', nl=False, fg='white') |
| 3359 | + click.secho('|', fg='white') |
| 3360 | + for dir_index in range(1, len(value)): |
| 3361 | + click.secho('|' + ' ' * 20 + '+', fg='white', nl=False) |
| 3362 | + click.secho('-' * 39 + '+', fg='white') |
| 3363 | + click.secho('|', nl=False, fg='white') |
| 3364 | + click.secho(f'{"":^20}', nl=False, fg='white') |
| 3365 | + click.secho('|', nl=False, fg='white') |
| 3366 | + click.secho(f'{value[dir_index]:^39}', nl=False, fg='white') |
| 3367 | + click.secho('|', fg='white') |
| 3368 | + click.secho('+' + '=' * 60 + '+', fg='white') |
| 3369 | + |
| 3370 | + |
| 3371 | +def style_log_line(line: str) -> str: |
| 3372 | + """ |
| 3373 | + Utility function for changing the color of lines and words in the logfiles when print them. |
| 3374 | +
|
| 3375 | + :param line: the line to be printed. |
| 3376 | +
|
| 3377 | + :return: the line with style we defined. |
| 3378 | + """ |
| 3379 | + |
| 3380 | + date_pattern = r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3}" |
| 3381 | + log_type_pattern = r"INFO|ERROR|WARNING|DEBUG" |
| 3382 | + file_path_pattern = r'(?<=File ")(.*?)(?=")' |
| 3383 | + line_number_pattern = r'(?<=line )\d+' |
| 3384 | + |
| 3385 | + date_match = re.search(date_pattern, line) |
| 3386 | + if date_match: |
| 3387 | + date_str = click.style(date_match.group(), fg='yellow') |
| 3388 | + line = line.replace(date_match.group(), date_str) |
| 3389 | + |
| 3390 | + log_type_match = re.search(log_type_pattern, line) |
| 3391 | + if log_type_match: |
| 3392 | + log_type = log_type_match.group() |
| 3393 | + color = 'green' if log_type == 'INFO' else 'red' if log_type == 'ERROR' else 'blue' |
| 3394 | + log_type_str = click.style(log_type, fg=color, bold=True) |
| 3395 | + line = line.replace(log_type, log_type_str) |
| 3396 | + |
| 3397 | + file_path_match = re.search(file_path_pattern, line) |
| 3398 | + if file_path_match: |
| 3399 | + file_path_str = click.style(file_path_match.group(), fg='cyan', bold=False) |
| 3400 | + line = line.replace(file_path_match.group(), file_path_str) |
| 3401 | + |
| 3402 | + line_number_match = re.search(line_number_pattern, line) |
| 3403 | + if line_number_match: |
| 3404 | + line_number_str = click.style(line_number_match.group(), fg='magenta', bold=False) |
| 3405 | + line = line.replace(line_number_match.group(), line_number_str) |
| 3406 | + |
| 3407 | + return line |
| 3408 | + |
| 3409 | + |
| 3410 | +def list_logfile(ip: str, logfile_name: str) -> None: |
| 3411 | + """ |
| 3412 | + Utility function for listing logfiles |
| 3413 | +
|
| 3414 | + :param ip: the ip of the node to list logfiles |
| 3415 | + :param logfile_name: the file name to retrieve |
| 3416 | +
|
| 3417 | + :return: None |
| 3418 | + """ |
| 3419 | + import csle_common.constants.constants as constants |
| 3420 | + from csle_common.metastore.metastore_facade import MetastoreFacade |
| 3421 | + config = MetastoreFacade.get_config(id=1) |
| 3422 | + for node in config.cluster_config.cluster_nodes: |
| 3423 | + if node.ip == ip or ip == "": |
| 3424 | + logfile_info = ClusterController.get_log_file( |
| 3425 | + ip=ip, port=constants.GRPC_SERVERS.CLUSTER_MANAGER_PORT, log_file_name=logfile_name) |
| 3426 | + error_block = False |
| 3427 | + for key, value in logfile_info.items(): |
| 3428 | + click.secho(key) |
| 3429 | + for i, line in enumerate(value): |
| 3430 | + styled_line = style_log_line(line) |
| 3431 | + |
| 3432 | + if "ERROR" in line and not error_block: |
| 3433 | + click.secho("\n" + "=" * 80, fg='red', bold=True) |
| 3434 | + error_block = True |
| 3435 | + |
| 3436 | + next_line_starts_log = \ |
| 3437 | + (i + 1 < len(value) and re.match( |
| 3438 | + r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} - (INFO|ERROR|WARNING|DEBUG)", |
| 3439 | + value[i + 1])) |
| 3440 | + if error_block and (next_line_starts_log or i == len(value) - 1): |
| 3441 | + click.secho(styled_line) |
| 3442 | + click.secho("=" * 80 + "\n", fg='red', bold=True) |
| 3443 | + error_block = False |
| 3444 | + else: |
| 3445 | + click.secho(styled_line) |
| 3446 | + |
| 3447 | + if error_block: |
| 3448 | + click.secho("=" * 80 + "\n", fg='red', bold=True) |
| 3449 | + error_block = False |
| 3450 | + |
| 3451 | + |
3330 | 3452 | def list_filebeats(ip: str, emulation: str, ip_first_octet: int) -> None:
|
3331 | 3453 | """
|
3332 | 3454 | Utility function for listing filebeats
|
|
0 commit comments