Showing posts with label Javascript. Show all posts
Showing posts with label Javascript. Show all posts

29 March 2015

Detailed ELB Latency Percentiles with Lambda

Amazon's Elastic Load Balancer (ELB) gives you only one latency metric, aggregated over all requests, and only with the usual min, max and average statistics. The value of this information is very poor. For example, when our first service went live in the Cloud, we monitored only the average latency, which was a very good and stable around 7ms. Later I found out that half of our traffic consists of OPTION requests (due to a CORS configuration error) which were handled in less than one millisecond, but users actually using the functionality of our service experienced a latency between 100ms and 800ms. Problem was that those users were only a few percent of the traffic, so the really important data was covered by noise and invisible inside the average. What we needed were url specific metrics and percentiles, especially the 99th ones.

Lambda to the rescue

As CloudWatch doesn't give us more detailed metrics we were on our own. Luckily, we can instruct the ELB to write its access logs every 5 minutes to an S3 bucket. All the raw data we need is already there. Tools like Graylog or the ELK stack could analyse them, but it takes some time to set up a pipeline that digests those logs continuously and produce the desired metrics. But AWS has a new service in its portfolio that helped us to get the desired data even faster: Lambda.
AWS Lambda is a service that runs your javascript code in response to events. One kind of event is the creation of an object in a s3 bucket, in our case every time the ELB writes its access log. The lambda javascript code runs inside nodejs, and AWS provides its complete API as a nodejs npm module. That gives us the possibility to read the access logs whenever they got written, calculate the percentiles we are interested in, and write them back to CloudWatch as custom metrics. As soon as we have our specialized ELB metrics available in CloudWatch we can visualize/graph them, create alarms and show them on our dashing dashboard that is already capable of integrating CloudWatch metrics. 
Data Flow

The Code

As a web developer I'm quite familiar with Javascript, but never really worked with nodejs before. Nevertheless, I started with the AWS lambda sample and was able to implement everything I want to do on one rainy saturday. And I could test everything locally in nodejs. Beautiful! 
I've created a repository with a simplified version of the ELB percentile to CloudWatch lambda to give you a quick start if you want to do similar stuff. You need to adjust the bucket names and group-by regex to your conditions. The complete logic lives in lambda.js, there are some local tests in test.js. The zip_lambda.sh creates the upload package.
Actually, I spent most of the time fighting with cross account access policies and setting up the correct lambda invocation and execution roles, because we are using a multiple account setup where logs and CloudWatch metrics are living in different accounts.  Another problem was the AWS CLI, I could not automate the lambda upload process and had to do it manually. The zip_lamda.sh creates the necessary command, but it never worked for me. When you create the lambda function, make the timeout big enough to be prepared for sunday evening traffic spikes ;-)

27 September 2012

Embed Url Links in TeamCity Build Logs

We at AutoScout24 are using TeamCity for our Continous Integration and Delivery. One step in our  Release Pipeline is integration testing in different browsers. If our test framework detects a problems it will create a screenshot of the breaking page. This screenshot contains valuable information that helps our developers to quickly analyze the issue. As an example, our test servers are configured to send stack traces which are visible in the screenshots.

But it seams that there is no way to include links in TeamCity build logs. TeamCity correctly escapes all the output from test and build tools so it is not possible to get some html into the log. So I investigated TeamCity extension points. Writing a complete custom html report seemed to be overkill because the test reporting tab worked really well. Writing a UI plugin means to learn Java, JSP and so on and as a .NET company we don't want to fumble around with the Java technology stack. But as a web company we know how to hack javascript ;-)

There is already a TeamCity plugin called StaticUIExtensions that allows you to embedd static html fragments in TeamCity pages. And because a script tag is a valid html fragment we could inject javascript into TeamCity. So I wrote a few lines of javascript that scan the dom for urls and transforms them into links. With this technique you get clickable links in all the build logs.


What you need to do:
  1. Install StaticUIExtensions 
  2. On your TeamCity server, open your "server\config\_static_ui_extensions" folder
  3. Open static-ui-extensions.xml
  4. Add a new rule that inserts "show-link.html" into every page that starts with "viewLog.html"
      <rule html-file="show-link.html" place-id="BEFORE_CONTENT">
        <url starts="viewLog.html" />
      </rule>
  5. Create a new file "show-link.html" with this content:
    <script>
      (function ($) {
        var regex = /url\((.*)\)/g
     
        function createLinksFromUrls() {
          $("div .fullStacktrace, div .msg").each(function () {
            var div = $(this);
            var oldHtml = div.html();
            var newHtml = oldHtml.replace(regex, "<a href='$1' target='_blank'>$1</a>");
            if (oldHtml !== newHtml) div.html(newHtml);
          });
        }
     
        $(document).ready(createLinksFromUrls);
        $(document).click(function () {
            window.setTimeout(createLinksFromUrls, 50);
            window.setTimeout(createLinksFromUrls, 100);
            window.setTimeout(createLinksFromUrls, 500);
        });
    })(window.jQuery); 
    
    </script>
    
This javascript searches for the url(*) pattern and replaces it with <a> tags.  Because TeamCity uses ajax to load the stacktraces when you expand a tree node, I used timers to delay the dom processing until the ajax call suceeded. Now you can log something like "url(http://www.autoscout24.de)" and this will be transformed to <a href="http://www.autoscout24.de">http://www.autoscout24.de</a>.

Voila, Mission completed.

17 June 2012

Visualizing a code repository with Bubble Charts and Circle Packing


German Version - English Version
Vor einiger Zeit bin ich über die freie Javascript Library d3.js gestolpert, die zur Visualisierung und Animation von  Daten in Webseiten dient. Da Datenvisualisierung eines meiner Hobbies ist und ich mich beruflich auch etwas mit Javascript beschäftige, lag es nahe sich dieses d3 etwas näher anzuschauen. Und es sollte sich lohnen, d3 rockt! Wirklich! Mit sehr wenig Aufwand, etwas Svg und Javascript hatte ich in einigen Stunden eine beeindruckende Visualisierung der Struktur eines sehr großen Source Code Repositories. Das Layouting und Rendering erledigt ein moderner Browser (IE9, Chrome, Safari oder Firefox) in wenigen Millisekunden. Ähnliches mit z.B. Graphviz und WPF als Rendering Engine zu implementieren wäre sehr viel aufwendiger, langsamer und unansehnlicher gewesen. Und da d3 im Browser läuft, ist die Visualisierung gleich plattformübergreifend verfügbar. Begeistert von den ersten Ergebnissen habe ich ausgehend von der ersten Spielerei gleich einige reale Probleme visualisiert. So sieht's heute aus:

Mein Arbeitgeber betreibt eine Website auf Basis von .NET und C#, an deren Entwicklung und Wartung sieben Teams seit einigen Jahren beteiligt sind. Dementsprechend viele Projekte gibt es im Repository. Große Projekte, kleine Projekte, wiederverwendete Projekte, exotische Projekte, tote Projekte, Jobs, Services und Web Anwendungen. Im Laufe der Zeit ging irgendwann die Übersicht verloren, welche Projekte wo benutzt werden, welches Team für welches Projekt zuständig ist, gegen welches Framework ein Projekt kompiliert, was eine gemeinsam genutzte  Komponente ist und was eine eigenständige Applikation sein sollte.
Mein Ziel war es, eine stark komprimierte Übersicht über die Projektstruktur zu geben und dabei die erwähnten Attribute zu visualisieren. Ursprünglich wollte ich dazu Treemaps verwenden, doch bei der Durchsicht der d3 Beispiele stieß ich auf Bubble Charts und Circle Packing die ich visuell ansprechender fand und die nach eigener Beschreibung "can pack hundreds of values into a small space" and "circle packing is not as space-efficient as a treemap, but it better reveals the hierarchy".
In der von mir verwendeten Variante wird jedes Projekt als ein Kreis ("Bubble") dargestellt. Jeder Kreis hat einen Namen, eine Größe (Durchmesser) und eine Farbe. Die Position der Bubbles innerhalb der Grafik ist durch den Packing Algorithmus bestimmt und kann nur in engen Grenzen (Sortierung) beeinflusst werden. Dies ist jedoch nicht schlimm, weil die Projekte innerhalb einer hierarchischen Verzeichnisstruktur liegen. Verzeichnisse werden ebenfalls als Kreise dargestellt, wobei geschachtelte Verzeichnisse und Projekte im übergeordneten Kreis angeordnet werden (siehe Bild). Damit werden in der Hierarchie zusammengehörende Projekte auch räumlich nahe beieinander dargestellt. Im obigen Beispiel sind die Verzeichnisse blau gefärbt, je tiefer die Verschachtelung, desto tiefer der Farbton. Die Bubble Attribute Größe und Farbe können dynamisch zur Visualisierung jeweils zweier Projekteigenschaften verwendet werden. Die Größe des Kreises kann beispielsweise die Größe des Projekts (in Bytes), die Anzahl der Abhängigkeiten oder die Anzahl der Verwender visualisieren. Jedes numerische Attribut kann auf den Durchmesser gemappt werden. Diskrete Werte wie z.B. Team Zugehörigkeit, .NET Version oder Projekttyp können besser durch Farben visualisiert werden.
Nun gibt es noch die Abhängigkeitsbeziehungen zwischen den Projekten. Das Managen dieser Abhängigkeiten ist eine 'viel geliebte' Aufgabe aller Architekten und wird häufig als Dependency Graph oder Dependency Matrix visualisiert. Die Visualisierung der Abhängigkeiten war nicht mein Primärziel, aber oft ist diese Information sehr nützlich. Ich experimentierte daher mit Animationen um diese Beziehungen parallel darzustellen. Ein Klick auf ein Projekt lässt alle Projekte blinken, die von dem angeklickten Projekt verwendet werden. Hält man beim Klicken die Strg Taste gedrückt, blinken alle Projekte die das angeklickte Projekt verwenden. 

Warum eigentlich ...

mache ich mir die Mühe dieser Visualisierung? Nun, ich kann alle Projekte und mehrere Eigenschaften gleichzeitig sehen. Durch geschickte Farbgebung, z.B. rot für ungesunde Eigenschaften, stechen selbst kleine Probleme optisch heraus. So kann ich jeden Tag mit einem Blick Änderungen in der Projektstruktur feststellen. Ein anderer Anwendungsfall war die Umstellung auf .NET4: alte Projekte sind rot, umgestellte sind grün. So lässt sich der Fortschritt leicht beobachten, und wenn alle Projekte umgestellt gibt es nur noch grüne Kreise. Neue hinzugekommene Projekte, die mit einem alten Framework angelegte wurden, lassen sich so sofort erkennen. Insbesondere für die interaktive Erforschung der Projektstruktur und dem Finden von nicht offensichtlichen Abhängigkeiten ist die Verbildlichung für mich als visuell denkenden Menschen sehr hilfreich. Dazu müssen natürlich auch ad hoc neue Eigenschaften visualisiert werden können, und dafür ist Flexibilität von d3 im Zusammenspiel mit Web Standards außerordentlich hilfreich.

Die Technik

Ein kleines C# Programm analysiert die Projektdateien (*.csproj files) und erstellt ein json Datenobjekt, dass die Verzeichnisstruktur, den Abhängigkeitsgraph sowie die Projekteigenschaften enthält (Größe, Typ, Team, .NET Version). Einige redundante Informationen wie leere Verzeichnisse oder Namens Prefixe werden in diesem Schritt entfernt. Das Datenobjekt misst unkomprimiert ca 120KB, und wird in ca 3s aus den Sourcen extrahiert. Dieses Objekt wird einmal pro Tag erzeugt und in eine statische WebSite kopiert. Das Javascript bubble.js übernimmt die Visualisierung im Browser. Dazu werden mit d3.js die Daten gelayoutet (d3.layout.pack()) und in SVG Elemente transformiert. Dies geschieht in wenigen Milisekunden. SVG bietet den Vorteil des flüssigen Zoomens und die grafischen Objekte bleiben als DOM Elemente erhalten und könnem mit Standard Events, wie MouseOver oder Clicks gescriptet werden. Daher ist ein moderner Browser mit SVG Unterstützung notwendig, z.B. Chrome, Safari, Firefox oder IE9. Erstaunlicherweise hat aktuell der IE9 die beste SVG Unterstützung, Chrome und Safari haben gröbere Probleme mit dem Textzooming und dem Hittesting. Firefox funktioniert gut, hat aber die schlechteste Performance. Das Javascript ist nach dem AMD Standard modularisiert, als AMD Loader wird mmd.js verwendet. Da ich zu Beginn die Funktionsweise des Circle Packing noch nicht genau kannte und auch noch nicht exakt wusste, welche Eigenschaften sinnvoll  visualisiert werden konnten, existiert ein kleines User Interface (Standard Html) mit dem verschiedene Parameter geändert werden können. D3 animiert solche Änderungen automatisch mit eingebauten Transitionen. Z.B. könnte man damit die Veränderung des Repositories im Zeitverlauf animieren. Dies könnte ein weiteres Hobby Projekt von mir werden ... stay tuned ...

16 February 2011

Visual Studio 2010 Javascript Snippets for Jasmine

Because Resharper 5 does not support live templates for Javascript I’m forced to use the built in VS2010 snippets. The default Javascripts snippets are located here:

%ProgramFiles%\Microsoft Visual Studio 10.0\Web\Snippets\JScript\1033\JScript

The ‘1033’ locale ID may be different for your country. I’m using the following snippets for creating Jasmine specs:

describe

<CodeSnippet Format="1.1.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>describe</Title>
    <Author>Christian Rodemeyer</Author>
    <Shortcut>describe</Shortcut>
    <Description>Code snippet for a jasmine 'describe' function</Description>
    <SnippetTypes>
      <SnippetType>Expansion</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Declarations>
      <Literal>
        <ID>suite</ID>
        <ToolTip>suite description</ToolTip>
        <Default>some suite</Default>
      </Literal>
    </Declarations>
    <Code Language="jscript"><![CDATA[describe("$suite$", function () {
        $end$        
    });]]></Code>
  </Snippet>
</CodeSnippet>

it

<CodeSnippet Format="1.1.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>it</Title>
    <Author>Christian Rodemeyer</Author>
    <Shortcut>it</Shortcut>
    <Description>Code snippet for a jasmine 'it' function</Description>
    <SnippetTypes>
      <SnippetType>Expansion</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Declarations>
      <Literal>
        <ID>spec</ID>
        <ToolTip>spec description</ToolTip>
        <Default>expected result</Default>       
      </Literal>    
    </Declarations>
    <Code Language="jscript"><![CDATA[it("should be $spec$", function () {
        var result = $end$       
    });]]></Code>
  </Snippet>
</CodeSnippet>

func

<CodeSnippet Format="1.1.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>function</Title>
    <Author>Christian Rodemeyer</Author>
    <Shortcut>func</Shortcut>
    <Description>Code snippet for an anonymous function</Description>
    <SnippetTypes>
      <SnippetType>Expansion</SnippetType>
      <SnippetType>SurroundsWith</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Code Language="jscript"><![CDATA[function () {
        $selected$$end$
    }]]></Code>
  </Snippet>
</CodeSnippet>