Analysieren von Websiteprotokollen mithilfe einer benutzerdefinierten Python-Bibliothek mit Apache Spark-Cluster unter HDInsightAnalyze website logs using a custom Python library with Apache Spark cluster on HDInsight

Dieses Notebook veranschaulicht das Analysieren von Protokolldaten unter Verwendung einer benutzerdefinierten Bibliothek mit Apache Spark unter HDInsight.This notebook demonstrates how to analyze log data using a custom library with Apache Spark on HDInsight. Als benutzerdefinierte Bibliothek verwenden wir eine Python-Bibliothek namens iislogparser.py.The custom library we use is a Python library called iislogparser.py.

Tipp

Dieser Artikel ist auch als Jupyter Notebook für einen Spark-Cluster (Linux) verfügbar, den Sie in HDInsight erstellen.This article is also available as a Jupyter notebook on a Spark (Linux) cluster that you create in HDInsight. In der Notebook-Umgebung können Sie die Python-Ausschnitte direkt im Notebook ausführen.The notebook experience lets you run the Python snippets from the notebook itself. Wenn Sie dem Artikel innerhalb eines Notebooks folgen möchten, erstellen Sie einen Spark-Cluster, starten Sie ein Jupyter Notebook (https://CLUSTERNAME.azurehdinsight.net/jupyter), und führen Sie dann das Notebook Analyze logs with Spark using a custom library.ipynb (Analysieren von Protokollen mit Spark mithilfe einer benutzerdefinierten „library.ipynb“) im Ordner PySpark aus.To perform the article from within a notebook, create a Spark cluster, launch a Jupyter notebook (https://CLUSTERNAME.azurehdinsight.net/jupyter), and then run the notebook Analyze logs with Spark using a custom library.ipynb under the PySpark folder.

Voraussetzungen:Prerequisites:

Sie benötigen Folgendes:You must have the following:

Speichern von Rohdaten als RDDSave raw data as an RDD

In diesem Abschnitt verwenden wir das Jupyter Notebook, das einem Apache Spark-Cluster in HDInsight zugeordnet ist, zum Ausführen von Aufträgen, bei denen Ihre Beispielrohdaten verarbeitet und dann als Hive-Tabelle gespeichert werden.In this section, we use the Jupyter notebook associated with an Apache Spark cluster in HDInsight to run jobs that process your raw sample data and save it as a Hive table. Die Beispieldaten sind in einer CSV-Datei (hvac.csv) enthalten, die standardmäßig auf allen Clustern verfügbar ist.The sample data is a .csv file (hvac.csv) available on all clusters by default.

Nachdem Ihre Daten als Apache Hive-Tabelle gespeichert wurden, können wir im nächsten Abschnitt eine Verbindung mit der Hive-Tabelle herstellen. Hierzu verwenden wir BI-Tools wie Power BI und Tableau.Once your data is saved as an Apache Hive table, in the next section we will connect to the Hive table using BI tools such as Power BI and Tableau.

  1. Klicken Sie im Azure-Portalim Startmenü auf die Kachel für Ihren Spark-Cluster (sofern Sie die Kachel ans Startmenü angeheftet haben).From the Azure portal, from the startboard, click the tile for your Spark cluster (if you pinned it to the startboard). Sie können auch unter Alle durchsuchen > HDInsight-Cluster zu Ihrem Cluster navigieren.You can also navigate to your cluster under Browse All > HDInsight Clusters.

  2. Klicken Sie auf dem Blatt für den Spark-Cluster auf Cluster-Dashboard und anschließend auf Jupyter Notebook.From the Spark cluster blade, click Cluster Dashboard, and then click Jupyter Notebook. Geben Sie die Administratoranmeldeinformationen für den Cluster ein, wenn Sie dazu aufgefordert werden.If prompted, enter the admin credentials for the cluster.

    Hinweis

    Sie können auch das Jupyter Notebook für Ihren Cluster aufrufen, indem Sie in Ihrem Browser die folgende URL öffnen.You may also reach the Jupyter Notebook for your cluster by opening the following URL in your browser. Ersetzen Sie CLUSTERNAME durch den Namen Ihres Clusters:Replace CLUSTERNAME with the name of your cluster:

    https://CLUSTERNAME.azurehdinsight.net/jupyter

  3. Erstellen Sie ein neues Notebook.Create a new notebook. Klicken Sie auf Neu und dann auf PySpark.Click New, and then click PySpark.

    Erstellen eines neuen Jupyter NotebooksCreate a new Jupyter notebook

  4. Ein neues Notebook mit dem Namen „Untitled.pynb“ wird erstellt und geöffnet.A new notebook is created and opened with the name Untitled.pynb. Klicken Sie oben auf den Namen des Notebooks, und geben Sie einen Anzeigenamen ein.Click the notebook name at the top, and enter a friendly name.

    Angeben eines neuen Namens für das NotebookProvide a name for the notebook

  5. Da Sie ein Notebook mit dem PySpark-Kernel erstellt haben, müssen Sie keine Kontexte explizit erstellen.Because you created a notebook using the PySpark kernel, you do not need to create any contexts explicitly. Die Spark- und Hive-Kontexte werden automatisch für Sie erstellt, wenn Sie die erste Codezelle ausführen.The Spark and Hive contexts will be automatically created for you when you run the first code cell. Sie können zunächst die Typen importieren, die für dieses Szenario erforderlich sind.You can start by importing the types that are required for this scenario. Fügen Sie den folgenden Codeausschnitt in eine leere Zelle ein, und drücken Sie UMSCHALT+EINGABETASTE.Paste the following snippet in an empty cell, and then press SHIFT + ENTER.

     from pyspark.sql import Row
     from pyspark.sql.types import *
    
  6. Erstellen Sie unter Verwendung der bereits im Cluster verfügbaren Beispielprotokolldaten ein RDD.Create an RDD using the sample log data already available on the cluster. Die Daten stehen im standardmäßigen, dem Cluster zugeordneten Speicherkonto unter \HdiSamples\HdiSamples\WebsiteLogSampleData\SampleLog\909f2b.log zur Verfügung.You can access the data in the default storage account associated with the cluster at \HdiSamples\HdiSamples\WebsiteLogSampleData\SampleLog\909f2b.log.

     logs = sc.textFile('wasb:///HdiSamples/HdiSamples/WebsiteLogSampleData/SampleLog/909f2b.log')
    
  7. Rufen Sie einen Beispielprotokollsatz ab, um sich zu vergewissern, dass der vorherige Schritt erfolgreich ausgeführt wurde.Retrieve a sample log set to verify that the previous step completed successfully.

     logs.take(5)
    

    Es sollte eine Ausgabe angezeigt werden, die Folgendem ähnelt:You should see an output similar to the following:

     # -----------------
     # THIS IS AN OUTPUT
     # -----------------
    
     [u'#Software: Microsoft Internet Information Services 8.0',
      u'#Fields: date time s-sitename cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Cookie) cs(Referer) cs-host sc-status sc-substatus sc-win32-status sc-bytes cs-bytes time-taken',
      u'2014-01-01 02:01:09 SAMPLEWEBSITE GET /blogposts/mvc4/step2.png X-ARR-LOG-ID=2ec4b8ad-3cf0-4442-93ab-837317ece6a1 80 - 1.54.23.196 Mozilla/5.0+(Windows+NT+6.3;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/31.0.1650.63+Safari/537.36 - http://weblogs.asp.net/sample/archive/2007/12/09/asp-net-mvc-framework-part-4-handling-form-edit-and-post-scenarios.aspx www.sample.com 200 0 0 53175 871 46',
      u'2014-01-01 02:01:09 SAMPLEWEBSITE GET /blogposts/mvc4/step3.png X-ARR-LOG-ID=9eace870-2f49-4efd-b204-0d170da46b4a 80 - 1.54.23.196 Mozilla/5.0+(Windows+NT+6.3;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/31.0.1650.63+Safari/537.36 - http://weblogs.asp.net/sample/archive/2007/12/09/asp-net-mvc-framework-part-4-handling-form-edit-and-post-scenarios.aspx www.sample.com 200 0 0 51237 871 32',
      u'2014-01-01 02:01:09 SAMPLEWEBSITE GET /blogposts/mvc4/step4.png X-ARR-LOG-ID=4bea5b3d-8ac9-46c9-9b8c-ec3e9500cbea 80 - 1.54.23.196 Mozilla/5.0+(Windows+NT+6.3;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/31.0.1650.63+Safari/537.36 - http://weblogs.asp.net/sample/archive/2007/12/09/asp-net-mvc-framework-part-4-handling-form-edit-and-post-scenarios.aspx www.sample.com 200 0 0 72177 871 47']
    

Analysieren von Protokolldaten mithilfe einer benutzerdefinierten Python-BibliothekAnalyze log data using a custom Python library

  1. Die ersten Zeilen der oben gezeigten Ausgabe enthalten die Headerinformationen. Die restlichen Zeilen entsprechen jeweils dem im Header beschriebenen Schema.In the output above, the first couple lines include the header information and each remaining line matches the schema described in that header. Die Analyse solcher Protokolle ist nicht immer ganz einfach.Parsing such logs could be complicated. Daher verwenden wir eine benutzerdefinierte Python-Bibliothek (iislogparser.py), um Protokolle dieser Art leichter analysieren zu können.So, we use a custom Python library (iislogparser.py) that makes parsing such logs much easier. Standardmäßig ist diese Bibliothek in Ihrem Spark-Cluster in HDInsight unter /HdiSamples/HdiSamples/WebsiteLogSampleData/iislogparser.py enthalten.By default, this library is included with your Spark cluster on HDInsight at /HdiSamples/HdiSamples/WebsiteLogSampleData/iislogparser.py.

    Da sie jedoch nicht in PYTHONPATH enthalten ist, können wir sie nicht mithilfe einer Importanweisung wie import iislogparser verwenden.However, this library is not in the PYTHONPATH so we cannot use it by using an import statement like import iislogparser. Zur Verwendung dieser Bibliothek müssen wir sie an alle Workerknoten verteilen.To use this library, we must distribute it to all the worker nodes. Führen Sie den folgenden Codeausschnitt aus:Run the following snippet.

     sc.addPyFile('wasb:///HdiSamples/HdiSamples/WebsiteLogSampleData/iislogparser.py')
    
  2. iislogparser stellt die Funktion parse_log_line bereit, die None zurückgibt, wenn es sich bei einer Protokollzeile um eine Kopfzeile handelt. Handelt es sich dagegen um eine Protokollzeile, gibt die Funktion eine Instanz der Klasse LogLine zurück.iislogparser provides a function parse_log_line that returns None if a log line is a header row, and returns an instance of the LogLine class if it encounters a log line. Verwenden Sie die Klasse LogLine, um nur die Protokollzeilen aus dem RDD zu extrahieren:Use the LogLine class to extract only the log lines from the RDD:

     def parse_line(l):
         import iislogparser
         return iislogparser.parse_log_line(l)
     logLines = logs.map(parse_line).filter(lambda p: p is not None).cache()
    
  3. Rufen Sie einige extrahierte Protokollzeilen ab, um sich zu vergewissern, dass der Schritt erfolgreich ausgeführt wurde.Retrieve a couple of extracted log lines to verify that the step completed successfully.

    logLines.take(2)
    

    Die Ausgabe sollte in etwa wie folgt aussehen:The output should be similar to the following:

    # -----------------
    # THIS IS AN OUTPUT
    # -----------------
    
    [2014-01-01 02:01:09 SAMPLEWEBSITE GET /blogposts/mvc4/step2.png X-ARR-LOG-ID=2ec4b8ad-3cf0-4442-93ab-837317ece6a1 80 - 1.54.23.196 Mozilla/5.0+(Windows+NT+6.3;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/31.0.1650.63+Safari/537.36 - http://weblogs.asp.net/sample/archive/2007/12/09/asp-net-mvc-framework-part-4-handling-form-edit-and-post-scenarios.aspx www.sample.com 200 0 0 53175 871 46,
     2014-01-01 02:01:09 SAMPLEWEBSITE GET /blogposts/mvc4/step3.png X-ARR-LOG-ID=9eace870-2f49-4efd-b204-0d170da46b4a 80 - 1.54.23.196 Mozilla/5.0+(Windows+NT+6.3;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/31.0.1650.63+Safari/537.36 - http://weblogs.asp.net/sample/archive/2007/12/09/asp-net-mvc-framework-part-4-handling-form-edit-and-post-scenarios.aspx www.sample.com 200 0 0 51237 871 32]
    
  4. Die Klasse LogLine bietet ihrerseits einige hilfreiche Methoden. Hierzu zählt beispielsweise is_error(), um zu ermitteln, ob ein Protokolleintrag einen Fehlercode besitzt.The LogLine class, in turn, has some useful methods, like is_error(), which returns whether a log entry has an error code. Damit können Sie die Anzahl von Fehlern in den extrahierten Protokollzeilen berechnen und anschließend alle Fehler in einer anderen Datei protokollieren.Use this to compute the number of errors in the extracted log lines, and then log all the errors to a different file.

    errors = logLines.filter(lambda p: p.is_error())
    numLines = logLines.count()
    numErrors = errors.count()
    print 'There are', numErrors, 'errors and', numLines, 'log entries'
    errors.map(lambda p: str(p)).saveAsTextFile('wasb:///HdiSamples/HdiSamples/WebsiteLogSampleData/SampleLog/909f2b-2.log')
    

    Folgendes sollte angezeigt werden:You should see an output like the following:

    # -----------------
    # THIS IS AN OUTPUT
    # -----------------
    
    There are 30 errors and 646 log entries
    
  5. Sie können auch Matplotlib verwenden, um eine Visualisierung der Daten zu erstellen.You can also use Matplotlib to construct a visualization of the data. Wenn Sie also beispielsweise die Ursache von Anforderungen mit hoher Ausführungsdauer isolieren möchten, empfiehlt es sich unter Umständen, die Dateien zu ermitteln, deren Bereitstellung im Schnitt am längsten dauert.For example, if you want to isolate the cause of requests that run for a long time, you might want to find the files that take the most time to serve on average. Der folgende Codeausschnitt ruft die 25 Ressourcen mit der höchsten Anforderungsabwicklungsdauer ab.The snippet below retrieves the top 25 resources that took most time to serve a request.

    def avgTimeTakenByKey(rdd):
        return rdd.combineByKey(lambda line: (line.time_taken, 1),
                                lambda x, line: (x[0] + line.time_taken, x[1] + 1),
                                lambda x, y: (x[0] + y[0], x[1] + y[1]))\
                  .map(lambda x: (x[0], float(x[1][0]) / float(x[1][1])))
    
    avgTimeTakenByKey(logLines.map(lambda p: (p.cs_uri_stem, p))).top(25, lambda x: x[1])
    

    Folgendes sollte angezeigt werden:You should see an output like the following:

    # -----------------
    # THIS IS AN OUTPUT
    # -----------------
    
    [(u'/blogposts/mvc4/step13.png', 197.5),
     (u'/blogposts/mvc2/step10.jpg', 179.5),
     (u'/blogposts/extractusercontrol/step5.png', 170.0),
     (u'/blogposts/mvc4/step8.png', 159.0),
     (u'/blogposts/mvcrouting/step22.jpg', 155.0),
     (u'/blogposts/mvcrouting/step3.jpg', 152.0),
     (u'/blogposts/linqsproc1/step16.jpg', 138.75),
     (u'/blogposts/linqsproc1/step26.jpg', 137.33333333333334),
     (u'/blogposts/vs2008javascript/step10.jpg', 127.0),
     (u'/blogposts/nested/step2.jpg', 126.0),
     (u'/blogposts/adminpack/step1.png', 124.0),
     (u'/BlogPosts/datalistpaging/step2.png', 118.0),
     (u'/blogposts/mvc4/step35.png', 117.0),
     (u'/blogposts/mvcrouting/step2.jpg', 116.5),
     (u'/blogposts/aboutme/basketball.jpg', 109.0),
     (u'/blogposts/anonymoustypes/step11.jpg', 109.0),
     (u'/blogposts/mvc4/step12.png', 106.0),
     (u'/blogposts/linq8/step0.jpg', 105.5),
     (u'/blogposts/mvc2/step18.jpg', 104.0),
     (u'/blogposts/mvc2/step11.jpg', 104.0),
     (u'/blogposts/mvcrouting/step1.jpg', 104.0),
     (u'/blogposts/extractusercontrol/step1.png', 103.0),
     (u'/blogposts/sqlvideos/sqlvideos.jpg', 102.0),
     (u'/blogposts/mvcrouting/step21.jpg', 101.0),
     (u'/blogposts/mvc4/step1.png', 98.0)]
    
  6. Die Informationen können auch als Grafik dargestellt werden.You can also present this information in the form of plot. Als ersten Schritt beim Erstellen einer Grafik erstellen wir zunächst eine temporäre Tabelle AverageTime.As a first step to create a plot, let us first create a temporary table AverageTime. Die Tabelle gruppiert die Protokolle nach Zeit, um zu ermitteln, ob ungewöhnliche Latenzspitzen vorlagen.The table groups the logs by time to see if there were any unusual latency spikes at any particular time.

    avgTimeTakenByMinute = avgTimeTakenByKey(logLines.map(lambda p: (p.datetime.minute, p))).sortByKey()
    schema = StructType([StructField('Minutes', IntegerType(), True),
                         StructField('Time', FloatType(), True)])
    
    avgTimeTakenByMinuteDF = sqlContext.createDataFrame(avgTimeTakenByMinute, schema)
    avgTimeTakenByMinuteDF.registerTempTable('AverageTime')
    
  7. Sie können dann die folgende SQL-Abfrage ausführen, um alle Datensätze in der Tabelle AverageTime abzurufen.You can then run the following SQL query to get all the records in the AverageTime table.

    %%sql -o averagetime
    SELECT * FROM AverageTime
    

    Durch den Befehl %%sql gefolgt von -o averagetime wird sichergestellt, dass die Ausgabe der Abfrage lokal auf dem Jupyter-Server (in der Regel der Hauptknoten des Clusters) beibehalten wird.The %%sql magic followed by -o averagetime ensures that the output of the query is persisted locally on the Jupyter server (typically the headnode of the cluster). Die Ausgabe wird als Pandas -Dataframe mit dem angegebenen Namen averagetimebeibehalten.The output is persisted as a Pandas dataframe with the specified name averagetime.

    Folgendes sollte angezeigt werden:You should see an output like the following:

    SQL-AbfrageausgabeSQL query output

    Weitere Informationen zur %%sql-Magic finden Sie unter Mit %%sql-Magic unterstützte Parameter.For more information about the %%sql magic, see Parameters supported with the %%sql magic.

  8. Sie können nun Matplotlib verwenden, eine Bibliothek zur Visualisierung von Daten, um eine Grafik zu erstellen.You can now use Matplotlib, a library used to construct visualization of data, to create a plot. Da die Grafik aus dem lokal gespeicherten averagetime-Dataframe erstellt werden muss, muss der Codeausschnitt mit der %%local-Magic beginnen.Because the plot must be created from the locally persisted averagetime dataframe, the code snippet must begin with the %%local magic. Dadurch wird sichergestellt, dass der Code lokal auf dem Jupyter-Server ausgeführt wird.This ensures that the code is run locally on the Jupyter server.

    %%local
    %matplotlib inline
    import matplotlib.pyplot as plt
    
    plt.plot(averagetime['Minutes'], averagetime['Time'], marker='o', linestyle='--')
    plt.xlabel('Time (min)')
    plt.ylabel('Average time taken for request (ms)')
    

    Folgendes sollte angezeigt werden:You should see an output like the following:

    Matplotlib-AusgabeMatplotlib output

  9. Nach Ausführen der Anwendung empfiehlt es sich, das Notebook herunterzufahren, um die Ressourcen freizugeben.After you have finished running the application, you should shutdown the notebook to release the resources. Klicken Sie hierzu im Menü Datei des Notebooks auf die Option zum Schließen und Anhalten.To do so, from the File menu on the notebook, click Close and Halt. Dadurch wird das Notebook heruntergefahren und geschlossen.This will shutdown and close the notebook.

Weitere InformationenSee also

SzenarienScenarios

Erstellen und Ausführen von AnwendungenCreate and run applications

Tools und ErweiterungenTools and extensions

Verwalten von RessourcenManage resources