[PYTHON] Obtenez et analysez les journaux S3 Logging avec la nortification d'événements Lambda et plongez-vous dans BigQuery

Aperçu

Lors de l'utilisation de l'hébergement de site Web statique, il joue le rôle d'un journal d'accès et c'est une fonction de journalisation qui décharge le journal de la demande vers S3 vers le compartiment spécifié. Plongez dans BigQuery afin qu'il puisse être récupéré, analysé et analysé.

Préparation préalable

Environnement d'exécution Lambda

--Le runtime est Python 2.7 --Modules requis (version réellement utilisée entre parenthèses) --boto3 (Lambda par défaut) - pytz (2015.7) - gcloud (0.8.0)

Format du journal de journalisation S3 et schéma BigQuery

Format du journal

C'est écrit ici. https://docs.aws.amazon.com/AmazonS3/latest/dev/LogFormat.html

Expression régulière pour l'analyse des journaux

Sentiment que chaque étiquette correspond directement au nom de la colonne dans le schéma suivant.

^(?P<owner>[^ ]+) (?P<bucket>[^ ]+) \[(?P<datetime>.+)\](?P<remote_ip>[^ ]+) (?P<requester>[^ ]+) (?P<request_id>[^ ]+) (?P<operation>[^ ]+) (?P<key>[^ ]+) "(?P<method>[^ ]+) (?P<uri>[^ ]+) (?P<proto>.+)" (?P<status>[^ ]+) (?P<error>[^ ]+) (?P<bytes>[^ ]+) (?P<size>[^ ]+) (?P<total_time>[^ ]+) (?P<ta_time>[^ ]+) "(?P<referrer>.+)" "(?P<user_agent>.+)" (?P<version>.+)$

Schéma

Cela ressemble à ceci selon le format. La colonne datetime semble être meilleure pour le type TIMESTAMP, mais j'ai choisi STRING cette fois en raison des circonstances, comme je l'expliquerai en détail plus tard.

Nom de colonne Moule
owner STRING
bucket STRING
datetime STRING
remote_ip STRING
requester STRING
request_id STRING
operation STRING
key STRING
method STRING
uri STRING
proto STRING
status STRING
error STRING
bytes INTEGER
size INTEGER
total_time INTEGER
ta_time INTEGER
referrer STRING
user_agent STRING
version STRING

La source

Remplacez la partie «<votre - *>» selon le cas.

import os
import json
import urllib
import boto3
import re
import datetime
import pytz
from gcloud import bigquery

BQ_PROJECT = '<your-project-id>'
BQ_DATASET = '<your-dataset-name>'
BQ_TABLE = '<your-table-name>'

s3 = boto3.client('s3')
bq = bigquery.Client.from_service_account_json(
    os.path.join(os.path.dirname(__file__), 'bq.json'),
    project=BQ_PROJECT)
dataset = bq.dataset(BQ_DATASET)
table = dataset.table(name=BQ_TABLE)
table.reload()

pattern = ' '.join([
    '^(?P<owner>[^ ]+)',
    '(?P<bucket>[^ ]+)',
    '\[(?P<datetime>.+)\]',
    '(?P<remote_ip>[^ ]+)',
    '(?P<requester>[^ ]+)',
    '(?P<request_id>[^ ]+)',
    '(?P<operation>[^ ]+)',
    '(?P<key>[^ ]+)',
    '"(?P<method>[^ ]+) (?P<uri>[^ ]+) (?P<proto>.+)"',
    '(?P<status>[^ ]+)',
    '(?P<error>[^ ]+)',
    '(?P<bytes>[^ ]+)',
    '(?P<size>[^ ]+)',
    '(?P<total_time>[^ ]+)',
    '(?P<ta_time>[^ ]+)',
    '"(?P<referrer>.+)"',
    '"(?P<user_agent>.+)"',
    '(?P<version>.+)$'])
log_pattern = re.compile(pattern)

def to_int(val):
    try:
        ret = int(val)
    except ValueError:
        ret = None
    return ret

def lambda_handler(event, context):
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8')
    res = s3.get_object(Bucket=bucket, Key=key)
    body = res['Body'].read()
    rows = []

    for line in body.splitlines():
        matches = log_pattern.match(line)
        dt_str = matches.group('datetime').split(' ')[0]
        timestamp = datetime.datetime.strptime(
            dt_str, '%d/%b/%Y:%H:%M:%S').replace(tzinfo=pytz.utc)

        rows.append((
            matches.group('owner'),
            matches.group('bucket'),
            timestamp.strftime('%Y-%m-%d %H:%M:%S'),
            matches.group('remote_ip'),
            matches.group('requester'),
            matches.group('request_id'),
            matches.group('operation'),
            matches.group('key'),
            matches.group('method'),
            matches.group('uri'),
            matches.group('proto'),
            matches.group('status'),
            matches.group('error'),
            to_int(matches.group('bytes')),
            to_int(matches.group('size')),
            to_int(matches.group('total_time')),
            to_int(matches.group('ta_time')),
            matches.group('referrer'),
            matches.group('user_agent'),
            matches.group('version'),))
    print(table.insert_data(rows))

Précautions, etc.

Au fait, le déploiement de Lambda pour Python est mon travail, mais j'utilise ce qui suit. Il est encore en cours de développement, mais il devient plus pratique à utiliser normalement, alors essayez-le si vous le souhaitez. https://github.com/marcy-terui/lamvery

[^ 1]: recherche d'un moyen intelligent de transférer des informations confidentielles dans Lambda [^ 2]: où vous voulez la prise en charge de Python3 dès que possible

Recommended Posts

Obtenez et analysez les journaux S3 Logging avec la nortification d'événements Lambda et plongez-vous dans BigQuery
[AWS] Associez Lambda et S3 à boto3
Exporter les journaux CloudWatch vers S3 avec AWS Lambda (Pythyon ver)
[Python] Exportez régulièrement de CloudWatch Logs vers S3 avec Lambda