[PYTHON] Abrufen und Analysieren von S3-Protokollprotokollen mit Lambda-Ereignis-Nortifizierung und Eintauchen in BigQuery

Überblick

Bei Verwendung von statischem Website-Hosting spielt es eine Rolle als Zugriffsprotokoll. Es handelt sich um eine Protokollierungsfunktion, die das Protokoll der Anforderung an S3 an den angegebenen Bucket weiterleitet, eine Aktualisierungsbenachrichtigung (Ereignis-Nortifizierung) in den Ziel-Bucket einfügt und Lambda startet. Tauchen Sie in BigQuery ein, damit es abgerufen, analysiert und analysiert werden kann.

Vorbereitungen

Lambda-Ausführungsumgebung

S3 Protokollierungsprotokollformat und BigQuery-Schema

Protokollformat

Es ist hier geschrieben. https://docs.aws.amazon.com/AmazonS3/latest/dev/LogFormat.html

Regulärer Ausdruck zum Parsen von Protokollen

Das Gefühl, dass jede Beschriftung direkt dem Spaltennamen im nächsten Schema entspricht.

^(?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>.+)$

Schema

Es sieht je nach Format so aus. Die Spalte "datetime" scheint für den TIMESTAMP-Typ besser zu sein, aber ich habe diesmal STRING aufgrund der Umstände gewählt, wie ich später ausführlich erläutern werde.

Spaltenname Schimmel
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

Quelle

Bitte ersetzen Sie das <your - *> Teil entsprechend.

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))

Vorsichtsmaßnahmen usw.

Übrigens ist die Bereitstellung von Lambda für Python meine Arbeit, aber ich verwende Folgendes. Es befindet sich noch in der Entwicklung, aber es wird immer bequemer, es normal zu verwenden. Probieren Sie es also aus, wenn Sie möchten. https://github.com/marcy-terui/lamvery

[^ 1]: Suche nach einer intelligenten Möglichkeit, vertrauliche Informationen in Lambda zu übertragen [^ 2]: Wo Sie Python3-Unterstützung so schnell wie möglich wünschen

Recommended Posts

Abrufen und Analysieren von S3-Protokollprotokollen mit Lambda-Ereignis-Nortifizierung und Eintauchen in BigQuery
[AWS] Verknüpfen Sie Lambda und S3 mit boto3
Ausgabe von CloudWatch-Protokollen an S3 mit AWS Lambda (Pythyon ver)
[Python] Exportieren Sie regelmäßig mit Lambda aus CloudWatch-Protokollen nach S3