Welcome to the Blipboard monitoring service!
Blipboard is a cloud-based logging event collector and display. You send logging data as JSON to an HTTP endpoint and each request appears as a little blip on all open viewers. The viewers are web pages, and you can run one 24/7 on a wall in your office.
Logarithmic time:
The way event data is supposed to be presented
What Blipboard does different than any other service dealing with the visualization of time series data is that it displays time on a logarithmic scale.
Look at a board with activity. As events happen, new blips arrive in real time from the top in one of the columns.
Notice that blips at the top of the board appear to move faster: This is because that area is more recent and time has a greater resolution there. The blips then slow down until near the bottom they appear to stand still: That area is older, and time resolution there is more coarse. Those blips still move though, just very, very slowly.
Blips have a minimum thickness, so two blips in the same column are bound to touch each other eventually as they travel downwards: The lower one slows down faster than the upper, more recent one.
When that happens, the blips become visually indistinguishable. They are now only one blip - one that is a little thicker. Both Blipboard's server and browser components independently merge the respective data to save memory space - so that this space can support the higher time resolution in the more recent time region. This is a new form of lossy compression.
Rough usage overview
Blipboard runs on nodes shared by multiple users.
When you sign up, you can create a board and enable it on a node. This gives you access to endpoints to send logging data to via HTTP, as well as links to open the board's viewer with.
The endpoints accept JSON over HTTP in a fixed and flat format. Each request always results in one event - there is no batching. You should be able to use common logging frameworks to send the data.
The easiest way to open a viewer is to click on the respective link on your board page when logged in, but there is also the option to set up a display that runs 24/7 (the viewer is then authenticated by a cookie that was set by a prior installation step, the installation secret; for security reasons, such installation secrets never allow access to the details of a blip).
24/7 displays are a central feature:
You absolutely want to have a board running permanently on your wall!
The data beyond little rectangles
Blipboard is easy to integrate by application developers, and while you can potentially use it for other things, the service is tuned for the ingestion of application logs. If you are a developer, I take it that you think of a logging stream as a stream of events consisting of a logger name, a level, a message, a time when it occurs and potentially more.
You send such events one at a time to the endpoints in the form of one JSON object with the following fields:
label sec. level 2 |
A case insensitive string of lesser security concern Ie. a logger name such as "my-application.production.startup". I recommend dots as separators. This will be the only text that is potentially visible on 24/7 displays. |
---|---|
level sec. level 1 |
A log level such as "INFO" or "ERROR"; the blip's color is derived from this Supported are TRACE, DEBUG, INFO, WARN, ERROR, and FATAL |
msg_template sec. level 1 |
A logging message with placeholders, ie. "User {name} has logged in" The format of the template is not relevant - important is only to get to a channel key that defines a good class of messages (see the section below). |
message sec. level 0 |
A logging message without placeholders, ie. "User a.meyer has logged in" If you send the complete message, Blipboard holds on to the last one. |
details sec. level 0 |
Further details such as a stack trace Conceptually this is just like the "message" field, but it can contain markdown and is presented assuming a larger content. |
All fields are optional except the label, although both level and msg_template are highly recommended if they make sense in your case.
Logged-in users - as opposed to unattended 24/7 displays - can see that data by clicking on a column.
The caveat: There are 100 channels in a board
Blipboard only ever stores the latest value for the details and message fields! Here's why that makes sense:
Each blip lives in a column, also called channel. Which channel it lives in is decided by the channel key, which is formed from the (label, level, msg_template) triple.
When a post is made with a new value for that triple, a new channel is assigned to it and the blip lives there. Otherwise, the assigned channel is used.
Note that in most application logs, the same logger name and message template is duplicated many times. Now think of each of those groups of similar messages as the channels: Blipboard can store only a 100 of those, but it's very good at also storing and displaying when and how often each of them occured.
For you as a user, the best case scenario is that you already use parameterized logging in your applications and can so easily send a proper msg_template (ie. a message template of which there probably are only a few per logger) to the endpoint. In that case, it's likely that you don't have more than 100 triples and things will work for you out of the box.
Sadly, not everyone has parameterized logging set up and there are also cases where one wants to assign channels more liberally. One situation, for example, would be to log the URL of incoming requests in a web application. Clearly we can't use a channel for each different URL as that would easily be too much. On the other hand, putting all requests in only one channel is too coarse.
It is likely that you benefit from thinking a bit about how your events should map on the channel real estate that you have.
When you run out of channels, the one with the oldest most recent event is simply discarded and a warning blip in one of the reserved system channels appears. This tells you that you may want to rethink channel usage.
An example with NLog
While when using .NET you’d normally just use the NLog Blipoard target, we’re going through a configuration with only pure NLog features to give an idea how to configure Blipboard with any logging frameowrk.
Let’s first assume you let NLog do the templating, which make things easier.
You’re using logging statements of the form
log.Info("User {0} has logged in.", userName);
or
log.Info("User {user} has logged in.", userName);
rather than
log.Info(String.Format("User {0} has logged in.", userName));
or
log.Info($"User {userName} has logged in."));
The last two make the parameter replacements in the string before NLog gets it.
The first two give NLog access to the template string though, which is constant over all calls from that line. That constant string is a very sensible choice for a channel key.
This is how the target definition could look like:
<target
xsi:type="Network"
name="MyBlipboard"
onOverflow="Error"
maxMessageSize="3500"
connectionCacheSize="1"
onConnectionOverflow="Block"
address="<some endpoint address>"
>
<layout xsi:type="JsonLayout">
<attribute name="label" layout="${logger}" />
<attribute
name="msg_template"
layout="${message:raw=true:truncate=240}}" />
<attribute name="message" layout="${message:truncate=240}" />
<attribute name="level" layout="${uppercase:${level}}" />
<attribute name="details" layout="${exception:format=tostring:truncate=2000}" />
</layout>
</target>
With this configuration, Blipboard will assign a channel for each triple (logger, message template, level).
This means that for every logging line in your code, you will get a channel, and with it the information when it got hit as well as the last values of the actual message and exception.
The various limitation modifiers will prevent message loss due to exceeded limits.
Fixing a good channel key
If you only have a message that contains variable parts, you will have to clean them out.
In the following sample four different variable things are replaced with a placeholder symbol to collapse many logging messages into using a common channel:
<variable
name="regex-collapse-numbers"
value="((?<![\\w+-])[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)" />
<variable
name="regex-collapse-guids"
value="([0-9A-Fa-f]\{8\}-([0-9A-Fa-f]\{4\}-)\{3\}[0-9A-Fa-f]\{12\})" />
<variable
name="regex-collapse-quotes"
value="("[^"]*")" />
<variable
name="regex-collapse-brackets"
value="\\[[^[]*\\]" />
<variable
name="regex-collapse"
value="${regex-collapse-quotes}|${regex-collapse-brackets}|${regex-collapse-addresses}|${regex-collapse-guids}|${regex-collapse-numbers}" />
<targets>
<target
xsi:type="Network"
name="MyBlipboard"
onOverflow="Error"
maxMessageSize="3500"
connectionCacheSize="1"
onConnectionOverflow="Block"
address="<some endpoint address>"
>
<layout xsi:type="JsonLayout">
<attribute name="label" layout="${logger}" />
<attribute
name="msg_template"
layout="${replace:regex=true:searchFor=${regex-collapse}:replaceWith=*:inner=${message}:truncate=240}" />
<attribute name="message" layout="${message:truncate=240}" />
<attribute name="level" layout="${uppercase:${level}}" />
<attribute name="details" layout="${exception:format=tostring:truncate=2000}" />
</layout>
</target>
</targets>
The first two collapse numbers and guids, something you’re not likely to want as part of a channel key.
The last two allow you to quick-fix logging statements such as
log.Info(String.Format("User {0} has logged in.", userName));
by changing them to
log.Info(String.Format("User \"{0}\" has logged in.", userName));
Security
Logs can potentially contain sensitive information such as stack traces.
Blipboard divides all data into four levels of decreasing security concern:
Level | Protection | |
---|---|---|
0 | The details and message fields. They are shown only on clicking on a lane by an authenticated user. | Authenticated HTTPS |
1 | The rest of the channel key fields, especially msg_template. They are only shown in the key overlay on mouse movement to an authenticated user. | AES encryption |
2 | The labels. They are shown to authenticated users and optionally also on 24/7 displays in the background. | AES encryption |
3 | The blips. They are shown on all displays. | Unprotected |
The AES encryption relies on permanent keys (created on enabling the board) that are fetched with an access secret in the installation cookie in the (less secure) case of an installed display. This fetch happens once per startup, and as long as the viewer runs, the display will show security level 2 data.*
The blips (ie. the non-textual part) are currently unprotected and only obscured by the board's unguessable id.
*Even more details, for those who really want to know: Of course the session cookie that authenticates logged-in users is not too different from the installation secret, but session cookies have a short lifetime, are refreshed before expiration, and lead to asking the user to log in again when expired before being refreshed. This would be annoying on installed displays and that makes those somewhat less secure.
Another issue is that security levels 1-3 are served without authentication on the data endpoints themselves. Instead, the data comes encrypted for levels 1-2 (in addition to the TLS layer of HTTPS). This will allow HTTP caching in the future and thwarts CORS preflight requests. The requirements of Blipboard here are somewhat similar to that of video streaming.
The encryption keys, however, change only when the board is reset. If a malicious party gets hold of them (by having a login or stealing a 24/7 display device with an active installation cookie), they will be able to decrypt security level 2 data for as long as the board isn't reset. The same applies to secruity level 1 data even, but at least such keys aren't served for installation secrets as 24/7 displays don't need them. Most importantly though, none of these issues apply at all to the truly sensitive message and details field, which can only be accessed with another kind of (and this time indeed fast-expiring) access token that is served only with a valid session cookie.
If you digested all that, you know why there are indeed 4 security levels.