бесплатная реализация подсчета пользовательских сессий из журнала веб-сервера? - PullRequest
3 голосов
/ 23 сентября 2010

Анализаторы журнала веб-сервера (например, Urchin) часто отображают несколько «сеансов».Сеанс определяется как серия посещений / кликов страниц, выполненных отдельным лицом в течение ограниченного непрерывного отрезка времени.Предпринята попытка идентифицировать эти сегменты с использованием IP-адресов и часто дополнительной информации, такой как пользовательский агент и ОС, а также порогового значения времени ожидания сеанса, например 15 или 30 минут.

Для определенных веб-сайтов и приложений пользовательможет быть авторизован и / или отслежен с помощью cookie, что означает, что сервер может точно знать, когда начинается сеанс.Я говорю не об этом, а об эвристическом выводе сессий (" реконструкция сессий "), когда веб-сервер их не отслеживает.

Я мог бы написать некоторый код, например, на Python, чтобы попытатьсяреконструировать сеансы на основе вышеупомянутых критериев, но я бы не стал изобретать велосипед.Я просматриваю файлы журналов размером около 400 тыс. Строк, поэтому я должен быть осторожен в использовании масштабируемого алгоритма.

Моя цель - извлечь список уникальных IP-адресов из файла журнала.и для каждого IP-адреса - количество сеансов, выведенных из этого журнала.Абсолютная точность и точность не нужны ... довольно хорошие оценки в порядке.

На основании этого описания :

новый запрос помещен всуществующий сеанс, если выполняются два условия:

  • IP-адрес и пользовательский агент совпадают с запросами, уже вставленными в сеанс
    ,
  • запрос выполненменее чем через пятнадцать минут после последнего вставленного запроса.

теоретически было бы просто написать программу на Python для создания словаря (с ключом по IP) словарей (по ключу пользователя).агент), значение которого равно паре: (количество сеансов, последний запрос последнего сеанса).

Но я бы предпочел использовать существующую реализацию, если она доступна, так как в противном случае я мог бы рискнуть потратить много временинастройка производительности.

К вашему сведению, чтобы кто-то не спросил пример ввода, вот строка нашего файла журнала (санированная):

#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status 
2010-09-21 23:59:59 215.51.1.119 GET /graphics/foo.gif - 80 - 128.123.114.141 Mozilla/5.0+(Windows;+U;+Windows+NT+5.1;+en-US;+rv:1.9.2)+Gecko/20100115+Firefox/3.6+(.NET+CLR+3.5.30729) http://www.mysite.org/blarg.htm 200 0 0

1 Ответ

2 голосов
/ 23 сентября 2010

ОК, если нет другого ответа, вот моя реализация Python.Я не эксперт по Python.Приветствуются предложения по улучшению.

#!/usr/bin/env python

"""Reconstruct sessions: Take a space-delimited web server access log
including IP addresses, timestamps, and User Agent,
and output a list of the IPs, and the number of inferred sessions for each."""

## Input looks like:
# Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status
# 2010-09-21 23:59:59 172.21.1.119 GET /graphics/foo.gif - 80 - 128.123.114.141 Mozilla/5.0+(Windows;+U;+Windows+NT+5.1;+en-US;+rv:1.9.2)+Gecko/20100115+Firefox/3.6+(.NET+CLR+3.5.30729) http://www.site.org//baz.htm 200 0 0

import datetime
import operator

infileName = "ex100922.log"
outfileName = "visitor-ips.csv"

ipDict = {}

def inputRecords():
    infile = open(infileName, "r")

    recordsRead = 0
    progressThreshold = 100
    sessionTimeout = datetime.timedelta(minutes=30)

    for line in infile:
        if (line[0] == '#'):
            continue
        else:
            recordsRead += 1

            fields = line.split()
            # print "line of %d records: %s\n" % (len(fields), line)
            if (recordsRead >= progressThreshold):
                print "Read %d records" % recordsRead
                progressThreshold *= 2

            # http://www.dblab.ntua.gr/persdl2007/papers/72.pdf
            #   "a new request is put in an existing session if two conditions are valid:
            #    * the IP address and the user-agent are the same of the requests already
            #      inserted in the session,
            #    * the request is done less than fifteen minutes after the last request inserted."

            theDate, theTime = fields[0], fields[1]
            newRequestTime = datetime.datetime.strptime(theDate + " " + theTime, "%Y-%m-%d %H:%M:%S")

            ipAddr, userAgent = fields[8], fields[9]

            if ipAddr not in ipDict:
                ipDict[ipAddr] = {userAgent: [1, newRequestTime]}
            else:
                if userAgent not in ipDict[ipAddr]:
                    ipDict[ipAddr][userAgent] = [1, newRequestTime]
                else:
                    ipdipaua = ipDict[ipAddr][userAgent]
                    if newRequestTime - ipdipaua[1] >= sessionTimeout:
                        ipdipaua[0] += 1
                    ipdipaua[1] = newRequestTime
    infile.close()
    return recordsRead

def outputSessions():
    outfile = open(outfileName, "w")
    outfile.write("#Fields: IPAddr Sessions\n")
    recordsWritten = len(ipDict)

    # ipDict[ip] is { userAgent1: [numSessions, lastTimeStamp], ... }
    for ip, val in ipDict.iteritems():
        # TODO: sum over on all keys' values  [(v, k) for (k, v) in d.iteritems()].
        totalSessions = reduce(operator.add, [v2[0] for v2 in val.itervalues()])
        outfile.write("%s\t%d\n" % (ip, totalSessions))

    outfile.close()
    return recordsWritten

recordsRead = inputRecords()

recordsWritten = outputSessions()

print "Finished session reconstruction: read %d records, wrote %d\n" % (recordsRead, recordsWritten)

Обновление: на ввод и обработку 342 тыс. Записей и запись 21 тыс. Записей ушло 39 секунд.Это достаточно хорошая скорость для моих целей.Видимо, 3/4 этого времени было потрачено на strptime()!

...