---
category: blog
date: 2021-07-12T18:50:00+13:00
description: I teach you some tricks on introspecting your Hugo builds
slug: hugo-debug-reports
tags:
  - hugo
  - maintenance
  - meta
  - organisation
  - staticsites
title: Creating debug reports with Hugo inline shortcodes
---
Recently I discovered that [Hugo](https://gohugo.io) added support for [inline shortcodes](https://gohugo.io/templates/shortcode-templates/) like 30 versions ago.

According to [bep](https://github.com/bep), the reason I had never heard about them was simple:

<blockquote class="twitter-tweet" data-lang="en" data-dnt="true" data-theme="light"><p lang="en" dir="ltr">You didn&#39;t ask ... (we added that to get the <a href="https://twitter.com/getbootstrap?ref_src=twsrc%5Etfw">@getbootstrap</a> site on Hugo, they had lots of inline scripting) ...</p>&mdash; Bjørn Erik Pedersen (@bepsays) <a href="https://twitter.com/bepsays/status/1408348824083615745?ref_src=twsrc%5Etfw">June 25, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## A shortcode refresher

To give an idea of what this means, here's a reminder on how you were required to use shortcodes in the past:

```html
<!-- layouts/shortcodes/notice.html -->
<div class="notice">
  <h3>{{ .Get "title" }}</h3>
  {{ .Inner }}
</div>

<!-- content/blog/example-post.md -->
# This is an example post
{{ notice title="This is a notice" }}
This is the content inside of a notice shortcode
{{ /notice }}
```

<sup>Minor caveat with shortcode syntax[^syntax]</sup>

As you can see, the shortcode internals live in your `layouts` folder, and have access to your `page` context as well as all of the various Hugo functions. Your post is only able to pass parameters into the shortcode itself.

Now to be clear, there's absolutely nothing wrong with doing this. In principle, it's a good idea for your content to not have any awareness of how it's being rendered. If you were to change the internals of the notice shortcode once, all of the pages it appears in are instantly updated upon the next render.

In saying that, the introduction of inline shortcodes allows us to do some fun things:

```html
<!-- content/blog/example-post.md -->
# This is an example post
Check out some of these funny gags I wrote:
{{ readfile.inline }}
<ul>
  {{ range $.Site.Data.gags }}
  <li>{{ . }}</li>
  {{ end }}
</ul>
{{ /readfile.inline }}
```

<sup>Minor caveat with shortcode syntax[^syntax]</sup>

Don't believe me? Here's that same inline shortcode embedded in this very post:

> [!note] 🗞️ Don't believe everything you read online!
>
> Originally, this part would have the contents of what you see above.
> 
> I had moved to Astro and recreated this with MDX but now I'm slowly moving back to Astro so for now, this file is just plain Markdown again.
>
> You'll just have to take my word for it that this was a real thing (and will be again shortly)

If any of these look familiar, I just used an inline shortcode to read from the same file that powers the footer.

I haven't used inline shortcodes to their full potential yet but I'd like to use it to add a bit more flavour to posts in future where having a dedicated shortcode would be a bit overkill.

They'll always have their place of course! Pick the right tool for the job and all that.

Anyway, that brings me to the actual topic at hand: debug reports.

## Let Hugo debug itself for you

There are always some unknowns to any site like "Do any links throw a 404?" or "Are there posts without a description?" and to shed some light on the current situation, we can get a bit meta.

It's easiest if you just check out the [debug](/debug) section of my site for yourself but the short version is that I've been using inline shortcodes to write one off custom reports, that effectively answer these questions through introspection. That's just a fancy way of saying I write Hugo content (reports) that show the status of other Hugo content.

There isn't anything super complex at the moment but I used it to clean up posts where the [folder names didn't match slugs](https://utf9k.net/debug/file-url-match/) as an example.

They automatically update every time the site rebuilds so while I could keep a spreadsheet, this is a nice way of keeping that useful information close to where the action happens.

I made [a list of various reports](https://utf9k.net/debug/reports-todo/) that I'll consider generating going forward and some will be a bit more tricky than others.

In all likelihood, the most interesting ones will just be reading from data sources generated by external scripts running either locally or via a CI pipeline. It's nicer to see all this information on one place even if I could just read the logs from my terminal or a pipeline run.

Ah, and before I forget, the actual source for the reports [is visible on Github](https://github.com/marcus-crane/utf9k/tree/main/content/debug) so feel free to borrow anything you'd like to use for your own site. They're pretty naively written but they get the job done.

Hopefully I've given you something to consider and if you think of any interesting report types that aren't on my list, [I'd love to hear about them!](mailto:hello@utf9k.net)

[^syntax]: The above isn't actual syntax but near enough. If I were to type it properly, the shortcode would really render, whereas I'm trying to demonstrate the shortcode internals themselves. To find some real shortcode syntax, check out [this](https://gohugo.io/templates/shortcode-templates/) section of the Hugo docs.
