24 November 2023

Blog Observability with logs and traces with Grafana Faro

If you use Hugo to create a blog or website, as I do, and you use GitHub Pages to host the blog, it is hard to get observability signals in your usual observability stack. I have been using Grafana, Loki, Tempo and Prometheus for a long time, so using this stack makes sense to me.
You can use Google Analytics with Hugo, but I don’t like third party cookies. If you search for Google Analytics' and GDPR’ you will find quite a few articles about the concerns that exist on this topic. But even apart from that, I like to see what I can get into the observability stack that I know.

No webserver, no metrics and logs?!

When you run your own webserver with Apache or Nginx, the servers will produce access logs files. You can parse these files with all kind of tools and feed them into a logs storage. The webserver will also generate metrics as well, which you can scrape with tools like Telegraf or OpenTelemetry Collector and push that to Prometheus, Mimir or InfluxDB. But there is more than just the server side.

What is Grafana Faro?

Grafana Faro is a highly configurable open source JavaScript agent that can easily be embedded in web applications to collect real user monitoring (RUM) data: performance metrics, logs, exceptions, events, and traces.

Faro consists mainly of a Web SDK and a collector. The collector runs on the server that receives all the data and splits the data into logs and traces. These logs and traces can be stored in Loki and Tempo.


Grafana Faro has a Web SDK that runs in the browser and you can embed it in your frontend application. It is able to collect all kinds of information:

As this can be embedded in a frontend application, I can use it in my Hugo site.

Local setup or Grafana Cloud

Grafana Faro can be used in a local setup like this:

Local setup with Grafana agent

The Github repository of Grafana Faro contains configuration examples for a local setup:

Grafana Cloud

Grafana Cloud offers Frontend Observability, which is the Grafana Faro setup with predefined dashboards, but you are not limited to this. You can also create your own dashboards. In Grafana Cloud you can add a frontend application and give it a name.
NOTE: Set the CORS headers correctly, otherwise you will not be able to push data to it.

As last step you can see information like this:

The URL is the endpoint of the Grafana agent / collector at Grafana cloud. Similar as the agent with the local setup.

Integration with Hugo

Out of the box there is no integration with Hugo. But if it is not available, I can create my own.
This is what I did: https://github.com/cbos/hugo-faro-analytics

The module is basically the same javascript code that Grafana provides, but I made it configurable and available as a Hugo module. You can use it right away in your own Hugo environment if you like.

  1. Add the module as git submodule
git submodule add https://github.com/cbos/hugo-faro-analytics.git themes/faro-analytics
  1. Enable the module in config.toml of Hugo (or yaml or json if you use that)
    path = 'faro-analytics'
  1. Configure the module in the config.toml of Hugo
    endpoint = "https://url to the agent with receiver config or Grafana Cloud"
    name = "Name of your site"
    version = "Your version"
  1. Almost everything is ready now, you only need to add a partial to the header of each page.
    This might need a change in the template you use. What needs to be added is this:
{{ partial "faro-analytics/assets/js" . }}
  1. With the configurations done you can locally run hugo server and just open your own page. This will send the collector. When you run locally the environment will be development. In the build process to prepare for production it is common to set environment to production, that is automatically picked up by this module. So the data send from the prodution site is marked as production. That helps to make a distinction between local development and production.

  2. To each page the partial is added, it will automatically inject the observability code. If there are pages which you don’t want to get observability signals from, you can add this to a page:

  analyze: false

What about the metrics and traces?

How does the data look like which is send to the collector? And how do the traces look like? I will write a next post for that, it will be too much for this post otherwise.

Originally published on Cees’ blog at https://ceesbos.nl/posts/20231124-blog-observability-with-grafana-faro/.

Cees Bos

Observability enthusiast, always looking for ways to improve software with better observability and what new insights can be gained. Delivering reliable software is always my priority. Combining existing tools often results in new ways to get an even better view. I work for OpenValue as a software engineer and SRE.