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é.
--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)
C'est écrit ici. https://docs.aws.amazon.com/AmazonS3/latest/dev/LogFormat.html
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>.+)$
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 |
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))
bq.json
[^ 1]
--Dans le corps principal, la partie datetime
devrait pouvoir être analysée avec% d /% b /% Y:% H:% M:% S% z
, mais en raison d'un bogue dans Python <3.2,% z
peut être utilisé avec une erreur. Puisqu'il n'y a rien de tel, il s'agit d'une méthode irrégulière impliquant pytz
[^ 2]
--Originalement, il est correct de spécifier l'objet datetime dans la colonne de type TIMESTAMP, mais s'agit-il d'un bogue de gcloud (0.8.0)
? Notez que BigQuery est en secondes, mais essayer d'enregistrer en millisecondes entraînera une date impossible.
--Chaque élément du journal sera -
s'il n'y a pas de données à afficher. Notez que les éléments que vous voulez convertir en int seront une exception si vous les convertissez en ʻint ('-') `tels quels.
--Le Document officiel de Google Cloud Client for Python (gcloud) est ancien à certains endroits, donc [Source](https: // github) .com / GoogleCloudPlatform / gcloud-python) Il était nécessaire de l'implémenter pendant le visionnage (au 26 novembre 2015)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