<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jeremy Brayton</title>
    <description>The latest articles on DEV Community by Jeremy Brayton (@w0rddriven).</description>
    <link>https://dev.to/w0rddriven</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F322513%2F3c13dc27-694c-4b1f-9980-19c5e1a8b4c7.jpeg</url>
      <title>DEV Community: Jeremy Brayton</title>
      <link>https://dev.to/w0rddriven</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/w0rddriven"/>
    <language>en</language>
    <item>
      <title>Livebook Autosaves</title>
      <dc:creator>Jeremy Brayton</dc:creator>
      <pubDate>Wed, 14 Dec 2022 20:00:00 +0000</pubDate>
      <link>https://dev.to/w0rddriven/livebook-autosaves-184j</link>
      <guid>https://dev.to/w0rddriven/livebook-autosaves-184j</guid>
      <description>&lt;p&gt;Tell me if you've done this before. You write up a nice little prototype of an idea in Livebook. You then get distracted by life situations like eating, writing an email, or taking a nap. You feel the need to close Livebook or prune the multiple sessions you've had running for weeks now. Because you have a million tabs open (with a session manager) and too many in Livebook to individually check, you restart your computer and let it crash(TM). When you open up Livebook again, "Oh. Shiiiiit" you exclaim. Where the hell did that notebook go? I'm 100% sure I clicked the disk icon, what the hell? If you're like me, you may have created this forked Livebook from memory, possibly taking a better approach.&lt;/p&gt;

&lt;p&gt;There is a better way to handle this scenario. Livebook has had autosaves since 0.4:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/livebookdev/status/1467576154941009920" rel="noopener noreferrer"&gt;https://twitter.com/livebookdev/status/1467576154941009920&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The feature was added in this PR according to the changelog:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/livebook-dev/livebook/pull/736" rel="noopener noreferrer"&gt;https://github.com/livebook-dev/livebook/pull/736&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To find your autosave files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For the Desktop application and CLI in production: &lt;code&gt;~/Library/Application Support/livebook/autosaved/&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;On my machine this expands to the absolute path &lt;code&gt;/Users/jbrayton/Library/Application Support/livebook/autosaved/&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;For the dev environment: in &lt;code&gt;config/dev.exs&lt;/code&gt;, this is set as &lt;code&gt;config :livebook, :data_path, Path.expand("tmp/livebook_data/dev"&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;On my machine this expands to the absolute path &lt;code&gt;/Users/Shared/repositories/personal/elixir/livebook/tmp/livebook_data/dev/autosaved/&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;For the test environment: in &lt;code&gt;config/test.exs&lt;/code&gt; this is set as &lt;code&gt;Path.expand("tmp/livebook_data/test")&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;On my machine this expands to the absolute path &lt;code&gt;/Users/Shared/repositories/personal/elixir/livebook/tmp/livebook_data/test/autosaved/&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Notebooks are saved by day in the autosave directory and the date corresponds to when they were created (when you immediately click the New notebook button).&lt;/p&gt;

&lt;p&gt;To view or change your autosave directory in the CLI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;a href="http://localhost:8080/settings" rel="noopener noreferrer"&gt;http://localhost:8080/settings&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Or, if you're already in a notebook, click the Livebook icon in the top left and click &lt;code&gt;Settings&lt;/code&gt; under the &lt;code&gt;Home&lt;/code&gt; and &lt;code&gt;Learn&lt;/code&gt; links.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbraytonium.com%2F2022%2F12%2F15%2Flivebook-autosaves%2Fimages%2F2022%2F12%2Flivebook_cli_settings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbraytonium.com%2F2022%2F12%2F15%2Flivebook-autosaves%2Fimages%2F2022%2F12%2Flivebook_cli_settings.png" alt="Livebook CLI settings page" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the Desktop application, the port will be randomized but you can either change the URL to tack on &lt;code&gt;/settings&lt;/code&gt; after the port or click around to the settings page as described earlier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbraytonium.com%2F2022%2F12%2F15%2Flivebook-autosaves%2Fimages%2F2022%2F12%2Flivebook_app_settings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbraytonium.com%2F2022%2F12%2F15%2Flivebook-autosaves%2Fimages%2F2022%2F12%2Flivebook_app_settings.png" alt="Livebook Desktop application settings page" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tracing the Default Setting
&lt;/h2&gt;

&lt;p&gt;If you are curious as to how this setting gets configured, we can start by looking at &lt;code&gt;Livebook.Settings.default_autosave_path()&lt;/code&gt; in &lt;a href="https://github.com/livebook-dev/livebook/blob/main/lib/livebook/settings.ex#L32-L34" rel="noopener noreferrer"&gt;https://github.com/livebook-dev/livebook/blob/main/lib/livebook/settings.ex#L32-L34&lt;/a&gt;. We follow &lt;code&gt;Livebook.Config.data_path()&lt;/code&gt; to &lt;a href="https://github.com/livebook-dev/livebook/blob/main/lib/livebook/config.ex#L76-L78" rel="noopener noreferrer"&gt;https://github.com/livebook-dev/livebook/blob/main/lib/livebook/config.ex#L76-L78&lt;/a&gt; then the Erlang function &lt;code&gt;:filename.basedir(:user_data, "livebook")&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Running this in Livebook we get the output &lt;code&gt;"/Users/jbrayton/Library/Application Support/livebook"&lt;/code&gt;, precisely where the desktop app stores its files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding Files
&lt;/h2&gt;

&lt;p&gt;What lead me to this discovery, after vaguely remembering autosave was a thing, was looking for files on my computer. I purposefully install and use the &lt;code&gt;locate&lt;/code&gt; command because I find it far easier to use than remembering the &lt;code&gt;find -name&lt;/code&gt; syntax.&lt;/p&gt;

&lt;p&gt;Here's the output for checking that the word &lt;code&gt;autosave&lt;/code&gt; is in any directory or file name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⋊&amp;gt; ~ locate autosaved/ 
/Users/Shared/repositories/personal/elixir/livebook/tmp/livebook_data/dev/autosaved/2022_10_31/18_25_03_mapset_drills_hedh.livemd
/Users/Shared/repositories/personal/elixir/livebook/tmp/livebook_data/dev/autosaved/2022_11_03/18_12_21_teller_bank_challenge_pv4e.livemd
/Users/Shared/repositories/personal/elixir/livebook/tmp/livebook_data/dev/autosaved/2022_11_03/18_13_39_untitled_notebook_pidb.livemd
/Users/Shared/repositories/personal/elixir/livebook/tmp/livebook_data/dev/autosaved/2022_11_03/19_31_57_dockyard_academy_amas_p75r.livemd
/Users/Shared/repositories/personal/elixir/livebook/tmp/livebook_data/dev/autosaved/2022_11_03/20_02_17_intro_to_timescale_jm7r.livemd
/Users/Shared/repositories/personal/elixir/livebook/tmp/livebook_data/dev/autosaved/2022_11_08/11_10_21_untitled_notebook_ervg.livemd
/Users/Shared/repositories/personal/elixir/livebook/tmp/livebook_data/dev/autosaved/2022_11_22/19_15_12_untitled_notebook_p75e.livemd

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What I found interesting was that my files in &lt;code&gt;~/Library/Application Support/livebook/autosaved/&lt;/code&gt; did not show up. Had I not realized there could be different locations, I may have overlooked the notebook I was looking for all along. I have no clue why &lt;code&gt;locate&lt;/code&gt; doesn't scour the directories in &lt;code&gt;~/Library&lt;/code&gt; it should have access to but that's a problem for another day.&lt;/p&gt;

</description>
      <category>development</category>
      <category>web</category>
      <category>elixir</category>
      <category>livebook</category>
    </item>
    <item>
      <title>Introduction to DockYard Beacon CMS</title>
      <dc:creator>Jeremy Brayton</dc:creator>
      <pubDate>Thu, 01 Dec 2022 18:00:00 +0000</pubDate>
      <link>https://dev.to/w0rddriven/introduction-to-dockyard-beacon-cms-2m3l</link>
      <guid>https://dev.to/w0rddriven/introduction-to-dockyard-beacon-cms-2m3l</guid>
      <description>&lt;p&gt;In December of 2021, Brian Cardarella introduced DockYard Beacon CMS in this series of tweets:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/bcardarella/status/1474126383123247104?lang=en"&gt;https://twitter.com/bcardarella/status/1474126383123247104?lang=en&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over the course of the past year, I've created a sample project a total of 3 times to get a better understanding for how it operates. I haven't seen a ton of content on Beacon beyond announcement tweets, the mention in the ElixirConf 2022 keynote, and &lt;a href="https://beaconcms.org/"&gt;https://beaconcms.org/&lt;/a&gt;. This post covers the complete instructions in the &lt;a href="https://github.com/BeaconCMS/beacon"&gt;readme&lt;/a&gt; with some notes on where to go from here. I had run into a few snags at first but a lot of those initial pain points have been hammered out so far. While a basic "Hello World" sample project is great, I plan on expanding on the sample with deeper dives into how Beacon serves up content. It takes a few novel approaches I haven't seen before to create either a CMS that runs along your application or it can be centralized with multi-tenancy. One CMS can service all of your ancillary marketing sites, blogs, or wherever you need the content.&lt;/p&gt;

&lt;p&gt;The following instructions are also listed on the &lt;a href="https://github.com/w0rd-driven/beacon_sample_umbrella"&gt;sample application readme&lt;/a&gt; so you're welcome to skip them if you want to look at the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a top-level directory to keep our application pair. This is temporary as the project matures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clone &lt;a href="https://github.com/BeaconCMS/beacon"&gt;GitHub - BeaconCMS/beacon: Beacon CMS&lt;/a&gt; to &lt;code&gt;./beacon&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Start with our first step from the Readme&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to the umbrella project directory&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Initialize git&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commit the freshly initialized project&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Add :beacon as a dependency to both apps in your umbrella project&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;mix deps.get&lt;/code&gt; to install the dependencies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commit the changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Configure Beacon Repo&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commit the changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Create a BeaconDataSource module that implements Beacon.DataSource.Behaviour&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commit the changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make router (&lt;code&gt;apps/beacon_sample_web/lib/beacon_sample_web/router.ex&lt;/code&gt;) changes to cover Beacon pages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commit the changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add some components to your &lt;code&gt;apps/beacon_sample/priv/repo/seeds.exs&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;ecto.reset&lt;/code&gt; to create and seed our database(s).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We can skip to Step 22 now that the &lt;code&gt;SafeCode&lt;/code&gt; package works as expected.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This is typically where we run into issues with &lt;code&gt;safe_code&lt;/code&gt; on the inner content of the layout seed, specifically:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In Beacon's repository, remove &lt;code&gt;SafeCode.Validator.validate_heex!&lt;/code&gt; function calls from the loaders&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fix the seeder to work without SafeCode.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commit the seeder changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enable Page Management and the Page Management API in router (&lt;code&gt;apps/beacon_sample_web/lib/beacon_sample_web/router.ex&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commit the Page Management router changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Navigate to &lt;a href="http://localhost:4000/beacon/home"&gt;http://localhost:4000/beacon/home&lt;/a&gt; to view the main CMS page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Navigate to &lt;a href="http://localhost:4000/beacon/blog/beacon_is_awesome"&gt;http://localhost:4000/beacon/blog/beacon_is_awesome&lt;/a&gt; to view the blog post.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Navigate to &lt;a href="http://localhost:4000/page_management/pages"&gt;http://localhost:4000/page_management/pages&lt;/a&gt; to view the &lt;code&gt;Page Management&lt;/code&gt; section.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Playground
&lt;/h3&gt;

&lt;p&gt;We should put the page management through its paces to determine weak points.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add another more robust layout.

&lt;ol&gt;
&lt;li&gt;Can we bring in JS frameworks like Vue? My guess is no, the layout looks to start under a &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Inject javascript at the bottom, this should load at the bottom of our &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; section.&lt;/li&gt;
&lt;li&gt;Try CDN urls first, then localhost.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Add another stylesheet. How do we use &lt;code&gt;stylesheet_urls&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Add another more robust component.

&lt;ol&gt;
&lt;li&gt;Can we use LiveView slots here? We're on &lt;code&gt;0.17.7&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;A replica of Laravel Nova panel of pages. Welcome and Home are Laravel defaults. Users would be useful as we could integrate with &lt;code&gt;phx gen auth&lt;/code&gt;.

&lt;ol&gt;
&lt;li&gt;What migrations are possibly included by Phoenix? Only users?&lt;/li&gt;
&lt;li&gt;Add a user profile page.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The dependency &lt;code&gt;safe_code&lt;/code&gt; was a problem during my first two attempts.

&lt;ul&gt;
&lt;li&gt;The third attempt on 11/6/2022 has no issues so far.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;I ran into issues by failing to add a &lt;code&gt;BeaconWeb&lt;/code&gt; scope and adding it as &lt;code&gt;BeaconSampleWeb&lt;/code&gt; instead.

&lt;ul&gt;
&lt;li&gt;Navigating to &lt;a href="http://localhost:4000/page/home"&gt;http://localhost:4000/page/home&lt;/a&gt; throws an &lt;code&gt;UndefinedFunctionError&lt;/code&gt; as &lt;code&gt;function BeaconSampleWeb.PageLive. __live__ /0 is undefined (module BeaconSampleWeb.PageLive is not available)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;The sample isn't as "pristine" as I'd like due to the bug fix but it really shouldn't be a showstopper.

&lt;ul&gt;
&lt;li&gt;Fixed this as I generated a new repository. There really aren't a ton of steps.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;As of 3/16 page management only covers the page. The layout, component, and stylesheet models are not covered yet.&lt;/li&gt;
&lt;li&gt;Stylesheets are injected into the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; as inline &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tags.&lt;/li&gt;
&lt;li&gt;Layout sits under &lt;code&gt;&amp;lt;body&amp;gt;&amp;lt;div data-phx-main="true"&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Running the server (&lt;code&gt;mix phx.server&lt;/code&gt;) immediately boots our Beacon components before it shows the url.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>development</category>
      <category>web</category>
      <category>elixir</category>
      <category>liveview</category>
    </item>
    <item>
      <title>2021 So Far</title>
      <dc:creator>Jeremy Brayton</dc:creator>
      <pubDate>Sun, 14 Nov 2021 21:36:39 +0000</pubDate>
      <link>https://dev.to/w0rddriven/2021-so-far-ldk</link>
      <guid>https://dev.to/w0rddriven/2021-so-far-ldk</guid>
      <description>&lt;p&gt;Originally, I wrote up a post trying to give a 2020 - 2021 overview that got hosed with a local git repo of this blog. I'm using the moment to remind myself that backups are important. It's also important to complete ideas for posts or journals quickly, even if something doesn't feel complete. Letting those linger for days without a git commit that hit the server is a genuine problem and I need to at the very least create and push to a new branch often.&lt;/p&gt;

&lt;p&gt;One change that happened at the end of 2020, I started the &lt;a href="https://braytonium.com/journal/" rel="noopener noreferrer"&gt;journal&lt;/a&gt; section to try to capture bite-sized rough ideas. I had started a journal at work with notes in files like &lt;code&gt;Phoenix Developer Diary.txt&lt;/code&gt; and I looked for a solution to merge my different diaries. The excellent Claire Codes has an extremely consistent diary at &lt;a href="https://www.clairecodes.com/dev-diary/" rel="noopener noreferrer"&gt;clairecodes&lt;/a&gt; and served as my main source of inspiration.&lt;/p&gt;

&lt;p&gt;I've gone all-in learning Elixir by participating in my first &lt;a href="https://github.com/w0rd-driven/advent-of-code-elixir" rel="noopener noreferrer"&gt;Advent of Code&lt;/a&gt; in 2020. I tapered off pretty quickly as I had serious problems working through loops and control flow. Seeing other examples on Elixir Forum helped immensely as I had slowly gotten better at reading the code. Later on in the year, I decided to take a TodoMVC sample through to a &lt;a href="https://github.com/w0rd-driven/live_view_todo_mvc/blob/main/docs/index.md" rel="noopener noreferrer"&gt;LiveView version&lt;/a&gt; with a little help from other resources on the internet. I had also started &lt;a href="https://github.com/w0rd-driven/live_view_todo_mvc/blob/main/docs/diary/day01.md" rel="noopener noreferrer"&gt;a diary&lt;/a&gt; where I wanted to capture the approaches I took each day I worked on the example. I have a plan to try to tackle my version from scratch but I'm also looking at other application ideas.&lt;/p&gt;

&lt;p&gt;While the Advent of Code and TodoMVC was good to get my feet wet, I learned far more by pushing through &lt;a href="https://github.com/w0rd-driven/exercism-elixir" rel="noopener noreferrer"&gt;Exercism exercises&lt;/a&gt;. If you're on Exercism and curious, my solutions can be found &lt;a href="https://exercism.org/profiles/w0rd-driven/solutions" rel="noopener noreferrer"&gt;here&lt;/a&gt;. I highly recommend using Exercism to learn any language it covers as the recently released version 3 makes for a great experience. Exercises feel a bit more "real world" and less like brain teasers that happen to use programming concepts. Even if I happened to look at the &lt;code&gt;HINTS.md&lt;/code&gt; file, it never felt like cheating as it would only guide us toward a solution, not implement it.&lt;/p&gt;

&lt;p&gt;After attending the excellent ElixirConf 2021 virtually, I've started working with Livebook in a &lt;a href="https://github.com/w0rd-driven/livebook_notebooks" rel="noopener noreferrer"&gt;few examples&lt;/a&gt;. I wanted to highlight the 3 notebooks that use the excellent &lt;code&gt;spider_man&lt;/code&gt; package to crawl 3 websites: Elixir Jobs, Elixir Radar Jobs, and Elixir Companies. Parsing the DOM of each required slowly stretching far outside my comfort zone. It's also worth mentioning that in the &lt;code&gt;Elixir Jobs&lt;/code&gt; example, I left a problem I found under the &lt;code&gt;Sorting the Results&lt;/code&gt; section. Due to the zero-width space, the section throws the message &lt;code&gt;** (SyntaxError) nofile:5:1: unexpected token: "​" (column 1, code point U+200B)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Coming to the end of 2021, I'm looking forward to immersing myself deeper in the Elixir ecosystem. Livebook is also a great way to get your feet wet with Elixir concepts, like a powerful language scratchpad. There have been other life changes since January 2020 but those deserve separate posts when I can get to them. Fortunately, the pandemic hasn't been harsh on my family or extended family at all, which I consider an extreme blessing. I can't say we weren't impacted by the last 2 years but things could've been much worse.&lt;/p&gt;

</description>
      <category>personal</category>
      <category>web</category>
      <category>elixir</category>
      <category>liveview</category>
    </item>
    <item>
      <title>Gridsome - Multiple Instances of the Source Filesystem Plugin</title>
      <dc:creator>Jeremy Brayton</dc:creator>
      <pubDate>Sun, 26 Jan 2020 19:00:00 +0000</pubDate>
      <link>https://dev.to/w0rddriven/gridsome-multiple-instances-of-the-source-filesystem-plugin-57mh</link>
      <guid>https://dev.to/w0rddriven/gridsome-multiple-instances-of-the-source-filesystem-plugin-57mh</guid>
      <description>&lt;p&gt;In my &lt;a href="https://braytonium.com/2020/01/01/hey-there-gridsome/"&gt;last post&lt;/a&gt;, I mentioned the transition to Gridsome and it has been relatively pain free. I owe a lot of this to the existing community and the great list of &lt;a href="https://gridsome.org/starters/"&gt;starter resources&lt;/a&gt;. If a concept isn't explained or clear in the docs, chances are you can gain some insight from the various starters.&lt;/p&gt;

&lt;p&gt;One particular concept I had a problem with right out of the gate was how to use markdown files from multiple directories. I started with the post type to handle /year/month/day/title routes but I wanted to move to an equivalent of the generic page type from Hexo. In doing research to the search terms I could've used months ago, I stumbled on &lt;a href="https://github.com/gridsome/gridsome/issues/401"&gt;multiple&lt;/a&gt; &lt;a href="https://github.com/gridsome/gridsome/issues/370#issuecomment-483982506"&gt;issues&lt;/a&gt; that point out how to do it.&lt;/p&gt;

&lt;p&gt;In the file &lt;code&gt;gridsome.config.js&lt;/code&gt;, I use the following snippet in the plugins section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  use: '@gridsome/source-filesystem',
  options: {
    path: 'blog/articles/**/*.md',
    typeName: 'Article',
    refs: {
      authors: {
        typeName: 'Author',
        create: true
      },
    }
  }
},
{
  use: '@gridsome/source-filesystem',
  options: {
    path: 'blog/posts/**/*.md',
    typeName: 'Post',
    refs: {
      authors: {
        typeName: 'Author',
        create: true
      },
      categories: {
        typeName: 'Category',
        create: true
      },
      tags: {
        typeName: 'Tag',
        create: true
      },
    }
  }
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since Gridsome has a concept of pages already, I chose the word article to represent them instead. As an example, the &lt;a href="https://braytonium.com/portfolio/"&gt;portfolio&lt;/a&gt; page is an article type while this page represents a post type. While hindsight makes this seem intuitive now, I somehow had the impression that you were only allowed one plugin type for safety reasons.&lt;/p&gt;

&lt;p&gt;To point out something else, the &lt;a href="https://braytonium.com/portfolio/"&gt;portfolio&lt;/a&gt; page highlights a technique I didn't think was possible at the time. The parent portfolio page is an article type but all the subsequent child pages are markdown files in a separate portfolio directory as a portfolio type. In the plugins section of &lt;code&gt;gridsome.config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  use: '@gridsome/source-filesystem',
  options: {
    path: 'blog/portfolio/**/*.md',
    typeName: 'Portfolio',
    refs: {
      authors: {
        typeName: 'Author',
        create: true
      },
    }
  }
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Coming from Hexo, I opt for placing content in markdown files and having unique layouts defined in the various &lt;code&gt;pages&lt;/code&gt; and &lt;code&gt;templates&lt;/code&gt; files. As much as Gridsome is a generic website framework, I find that it can be extremely flexible to whatever workflow you wish to create. There are some parts of Hexo I miss like scaffolding new page types or steering me into blog concepts but the transition to Gridsome has been rather smooth. While Gridsome may not be for everyone, I can definitely see how JAMstack has gained traction recently. Barring very few gotchas, working on this site is fun again even in the I-can-see-every-blemish state it's currently in.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Hey there, Gridsome!</title>
      <dc:creator>Jeremy Brayton</dc:creator>
      <pubDate>Wed, 01 Jan 2020 20:00:00 +0000</pubDate>
      <link>https://dev.to/w0rddriven/hey-there-gridsome-1cam</link>
      <guid>https://dev.to/w0rddriven/hey-there-gridsome-1cam</guid>
      <description>&lt;p&gt;It's been over a year since my &lt;a href="https://braytonium.com/2018/07/10/laravel-passport-usage-with-swaggervel-v2-3/"&gt;last post&lt;/a&gt; and while unfinished drafts don't count, I thought my blog was due for a change. The move from Octopress to Hexo was relatively uneventful but I found keeping up a little difficult. It wasn't completely on Hexo, I had tweaked things to a point that merging in changes over time became cumbersome and slow. In a &lt;a href="https://braytonium.com/2016/04/17/jsonresume/"&gt;previous post&lt;/a&gt;, I roughly mentioned the transition and a lot has happened to the web in over 3 years.&lt;/p&gt;

&lt;p&gt;Static site generators like Hugo and Gatsby have picked up steam and the feature set of Gatsby, particularly the GraphQL component stood out. I wanted to stick to Vue for as many of my personal projects as possible, so I searched for any static site generator using Vue I could find. Fortunately Gridsome has come along as a nice clone of Gatsby using Vue rather than React and even though it's at v0.7.12 at the time of this post, I've run into very few hurdles.&lt;/p&gt;

&lt;p&gt;I don't have the best understanding of JAMstack after working with a sample size of one, but learning GraphQL by only dealing with queries has made this one of the best ways to get my feet wet. I'm by no means an expert but this light interaction compels me to use it more often, as it's mostly been a pleasure to work with. Frameworks like Gridsome and I suspect Gatsby let you focus on almost entirely the frontend. Even though the A in JAMstack stands for APIs, as a backend developer I haven't had to write a single REST, GraphQL or what I'd typically associate with an API like I would with Laravel, Phoenix Framework, or Express.&lt;/p&gt;

&lt;p&gt;One thing I miss about Hexo is that it had scaffolding to generate new files. Gridsome is a framework for generic sites, not just blogs, so scaffolding doesn't seem to be included. Coming from Hexo I wanted to keep as much of the existing markdown as possible and I think some of the approaches I've taken may be useful to others. A small example I had a problem understanding is that you can use a &lt;code&gt;@gridsome/source-filesystem&lt;/code&gt; plugin multiple times, one for each directory or type. It makes sense in hindsight but none of the starters used the technique nor did the docs seem to suggest it was possible. I'm tempted to create a starter based on my usage patterns but worst case, I plan on writing a post outlining some of these approaches in the near future.&lt;/p&gt;

&lt;p&gt;One last thing is a small humblebrag. While the theme for this site draws a few cues from the older version, I wanted to flex my design abilities by focusing on techniques I've learned reading &lt;a href="https://refactoringui.com/book/"&gt;Refactoring UI&lt;/a&gt;. By the time this post is published it likely won't be perfect but I think it's a decent first pass that should only get better over time.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Laravel Passport usage with Swaggervel v2.3</title>
      <dc:creator>Jeremy Brayton</dc:creator>
      <pubDate>Tue, 10 Jul 2018 20:30:00 +0000</pubDate>
      <link>https://dev.to/w0rddriven/laravel-passport-usage-with-swaggervel-v2-3-4789</link>
      <guid>https://dev.to/w0rddriven/laravel-passport-usage-with-swaggervel-v2-3-4789</guid>
      <description>&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;I've been using &lt;a href="https://github.com/appointer/swaggervel"&gt;this Swaggervel package&lt;/a&gt; with almost all my recent Laravel projects. A few instances were lightly customized to work against different authentication schemes and I only briefly touched on using Laravel Passport.&lt;/p&gt;

&lt;p&gt;I wanted to highlight a few areas while also offering up &lt;a href="https://github.com/w0rd-driven/laravel-passport-swaggervel-example"&gt;an example project&lt;/a&gt; as a lightly opinionated jumping off point. Just the highlights cover quite a bit of information but the example should have ample information in commit messages and in the finished product.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Laravel and Laravel Passport
&lt;/h3&gt;

&lt;p&gt;First we run &lt;code&gt;laravel new &amp;lt;project_name&amp;gt;&lt;/code&gt;, &lt;code&gt;git init&lt;/code&gt; and commit immediately to mark our base Laravel installation. I've always preferred this immediate commit over making customizations first as it's far easier to track your customizations versus the base install. Next, we run through &lt;a href="https://laravel.com/docs/5.6/passport"&gt;the Laravel Passport docs&lt;/a&gt; with the following caveats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;php artisan vendor:publish --tag=passport-migrations&lt;/code&gt; doesn't copy the migrations as expected. We manually do this.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;php artisan migrate --step&lt;/code&gt; creates a migration batch for each migration file individually. This lets us rollback to individual steps and is primarily personal preference.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app/Providers/AuthServiceProvider&lt;/code&gt; contains the following:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Passport::routes(function (RouteRegistrar $routeRegistrar) {
    $routeRegistrar-&amp;gt;all();
});
Passport::tokensCan([
]);
Passport::enableImplicitGrant();
Passport::tokensExpireIn(Carbon::now()-&amp;gt;addDays(15));
Passport::refreshTokensExpireIn(Carbon::now()-&amp;gt;addDays(30));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;artisan make:auth&lt;/code&gt; to utilize the app layout and create a &lt;code&gt;home&lt;/code&gt; view that is protected by the Login prompt.

&lt;ul&gt;
&lt;li&gt;The Passport Vue components could be displayed on the welcome page but we're attempting to set future users up for better practices.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Create a proper &lt;code&gt;WelcomeController&lt;/code&gt; with matching view that utilizes the same app layout

&lt;ul&gt;
&lt;li&gt;This is not necessary but this one step makes it possible to properly utilize &lt;code&gt;artisan route:cache&lt;/code&gt; in the future as route closures aren't supported.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Setting up Swaggervel
&lt;/h3&gt;

&lt;p&gt;Now that the basics are complete, we bring in Swaggervel via &lt;code&gt;composer require appointer/swaggervel --dev&lt;/code&gt;. We can ignore the line in the documentation that mentions adding &lt;code&gt;Appointer\Swaggervel\SwaggervelServiceProvider::class&lt;/code&gt; as that's only for Laravel versions earlier than 5.5 without package discovery. It's necessary to run &lt;code&gt;artisan vendor:publish&lt;/code&gt; to publish the content as we're using this package as a dev dependency and the assets won't show up otherwise. Now that Swaggervel is in place we can bring it all together.&lt;/p&gt;

&lt;p&gt;To start, we create the file &lt;code&gt;app/Http/Controllers/Api/v1/Controller.php&lt;/code&gt; as our generic API base controller. This controller houses our root-level &lt;code&gt;@SWG\Info&lt;/code&gt; definition in a convenient location. This also sets us up for future work where API controllers are versioned, though this is personal preference. The secret sauce is the &lt;code&gt;@SWG\SecurityScheme&lt;/code&gt; annotation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * @SWG\SecurityScheme(
 * securityDefinition="passport-swaggervel_auth",
 * description="OAuth2 grant provided by Laravel Passport",
 * type="oauth2",
 * authorizationUrl="/oauth/authorize",
 * tokenUrl="/oauth/token",
 * flow="accessCode",
 * scopes={
 * *
 * }
 * ),
 */
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;securityDefinition&lt;/code&gt; property is arbitrary but needs to be included in every protected route definition. You can specify multiple security schemes to cover things like an generic api key or likely multiple OAuth flows, though I haven't tried working out the latter.&lt;a href="https://swagger.io/specification/#oauthFlowsObject"&gt;These are the supported flows&lt;/a&gt; and it's important to note that Swaggervel is currently on the &lt;code&gt;OpenAPI 2.0&lt;/code&gt; specification, though this may change in the future. The &lt;code&gt;scopes&lt;/code&gt; specified includes everything (*) but we could define any scopes explicitly. It should be noted that we also need to setup the route definitions in our resource Controller classes but due to the verbosity they are too much to include in this post. A small snippet that is unique to working with this setup is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* security={
* {
* "passport-swaggervel_auth": {"*"}
* }
* },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells a specific endpoint to use the &lt;code&gt;securityDefinition&lt;/code&gt; created earlier and it's important that these match. The example project has rudimentary &lt;code&gt;UserController&lt;/code&gt;, &lt;code&gt;User&lt;/code&gt; model, and &lt;code&gt;UserRequest&lt;/code&gt; definitions that should be a decent starting point, though I can't vouch for them being very comprehensive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring our OAuth Client
&lt;/h3&gt;

&lt;p&gt;First we need to create an OAuth client specifically for Swaggervel connections. Go to the &lt;code&gt;/home&lt;/code&gt; endpoint and under &lt;code&gt;OAuth Clients&lt;/code&gt; click &lt;code&gt;Create New Client&lt;/code&gt;. Under &lt;code&gt;Name&lt;/code&gt; specify &lt;code&gt;Laravel Passport Swaggervel&lt;/code&gt; or just &lt;code&gt;Swaggervel&lt;/code&gt;. Under &lt;code&gt;Redirect URL&lt;/code&gt; we're unable to specify &lt;code&gt;/vendor/swaggervel/oauth2-redirect.html&lt;/code&gt; directly, so use a placeholder like &lt;code&gt;https://passport-swaggervel.test/vendor/swaggervel/oauth2-redirect.html&lt;/code&gt; instead. Using your SQL toolbox of choice, navigate to the table &lt;code&gt;oauth_clients&lt;/code&gt; and look for the row with the name specified in the previous step, in our case &lt;code&gt;Laravel Passport Swaggervel&lt;/code&gt;. Manually update the redirect column to &lt;code&gt;/vendor/swaggervel/oauth2-redirect.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now that our OAuth client in Passport should be setup correctly, we focus our attention on the &lt;code&gt;config/swaggervel.php&lt;/code&gt; settings. The &lt;code&gt;client-id&lt;/code&gt; should be set to what Passport shows in the UI as the &lt;code&gt;Client ID&lt;/code&gt; field. This is also the id of the row in the &lt;code&gt;oauth_clients&lt;/code&gt; table. The &lt;code&gt;client-secret&lt;/code&gt; should be set to the what Passport shows in the UI as the &lt;code&gt;Secret&lt;/code&gt; field. We also set both &lt;code&gt;secure-protocol&lt;/code&gt; and &lt;code&gt;init-o-auth&lt;/code&gt; to true, the latter of which fills in the UI with our secrets otherwise we'd have to put them in manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Correcting Swagger UI to Capture Tokens
&lt;/h3&gt;

&lt;p&gt;For the OAuth2 redirect to function properly we need to modify the Swagger UI configuration in &lt;code&gt;resources/views/vendor/swaggervel/index.blade.php&lt;/code&gt;. Under &lt;code&gt;const ui = SwaggerUIBundle({&lt;/code&gt; right below the url parameter should be &lt;code&gt;oauth2RedirectUrl: '/vendor/swaggervel/oauth2-redirect.html',&lt;/code&gt;. This reinforcement is necessary as the Swagger UI doesn't 'catch' the tokens properly without this. Other notable additions that make the UI slightly easier to work with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tagsSorter: 'alpha',
operationsSorter: 'alpha',
docExpansion: 'list',
filter: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing Authentication via the Swagger UI
&lt;/h3&gt;

&lt;p&gt;First we go to the &lt;code&gt;api/docs&lt;/code&gt; endpoint to display the Swagger UI. Click the &lt;code&gt;Authorize&lt;/code&gt; button with the unlocked padlock icon. Verify the &lt;code&gt;client_id&lt;/code&gt; and &lt;code&gt;client_secret&lt;/code&gt; sections are filled in. Click &lt;code&gt;Authorize&lt;/code&gt; and the Laravel Passport screen labelled &lt;code&gt;Authorization Request&lt;/code&gt; should display with the &lt;code&gt;Authorize&lt;/code&gt; and &lt;code&gt;Cancel&lt;/code&gt; buttons. Click &lt;code&gt;Authorize&lt;/code&gt; again and you should be redirected back to Swagger with the &lt;code&gt;client_id&lt;/code&gt; and &lt;code&gt;client_secret&lt;/code&gt; now showing as &lt;code&gt;******&lt;/code&gt; with a &lt;code&gt;Logout&lt;/code&gt; button instead of &lt;code&gt;Authorize&lt;/code&gt;. We should now be able to click on the &lt;code&gt;GET /users&lt;/code&gt; route, click the &lt;code&gt;Try it out&lt;/code&gt; button, click on the blue &lt;code&gt;Execute&lt;/code&gt; button and be greeted with our expected response as a list of users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;We've hopefully highlighted the basic touch points of the process with the example code going into much further detail. The project is lightly opinionated to facilitate practices that have served me well so far. It is by no means a complete reference but it should be a good jumping off point when it's somewhat harder to see the big picture without a comprehensive example.&lt;/p&gt;

&lt;p&gt;In case you need the &lt;a href="https://github.com/w0rd-driven/laravel-passport-swaggervel-example"&gt;link to the project again&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Scratching an Itch with Prometheus</title>
      <dc:creator>Jeremy Brayton</dc:creator>
      <pubDate>Thu, 05 Jul 2018 22:30:00 +0000</pubDate>
      <link>https://dev.to/w0rddriven/scratching-an-itch-with-prometheus-jaj</link>
      <guid>https://dev.to/w0rddriven/scratching-an-itch-with-prometheus-jaj</guid>
      <description>&lt;p&gt;Not too long ago I became obsessed with Prometheus. I'd heard about it for a while, knew it was powerful, and couldn't quite understand how everything fit together. The documentation is extremely verbose for good reason but it took playing with it for a while for everything to click.&lt;a href="https://ordina-jworks.github.io/monitoring/2016/09/23/Monitoring-with-Prometheus.html"&gt;This post&lt;/a&gt; is a rather concise and extensive overview that goes a long way in expressing the basic concepts to my developer brain. In their simplest form, exporters expose an HTTP endpoint of &lt;code&gt;/metrics&lt;/code&gt; with the output being statistics in Prometheus' format. The real power of Prometheus comes when you expose your own &lt;code&gt;/metrics&lt;/code&gt; endpoint and have Prometheus consume the statistics you generate.&lt;a href="https://blog.alexellis.io/prometheus-monitoring/"&gt;This post is also a very good introduction&lt;/a&gt; with the section &lt;code&gt;Building your own exporter&lt;/code&gt; being extremely valuable in describing just some of the possibilities.&lt;/p&gt;

&lt;p&gt;After getting my bearings I started with a prototype with a simple premise "Why look at the usage graphs in Digital Ocean for each server independently? Why not have it in one location?"&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-prometheus-on-ubuntu-16-04"&gt;How To Install Prometheus on Ubuntu 16.04&lt;/a&gt; is a very good primer to get everything up and running quickly.&lt;/p&gt;

&lt;p&gt;I've made a few modifications since working through the article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/prometheus/prometheus/releases/tag/v2.3.1"&gt;Prometheus version 2.3.1&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;There have been massive perf improvements in v2.3.x.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/prometheus/node_exporter/releases/tag/v0.16.0"&gt;node_exporter version 0.16.0&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;There are significant changes to the metrics naming conventions.&lt;/li&gt;
&lt;li&gt;This exporter typically has the most coupling with Grafana dashboards and often requires altering them to work correctly.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;prometheus:prometheus&lt;/code&gt; for ownership of core prometheus processes like &lt;code&gt;prometheus&lt;/code&gt; or &lt;code&gt;alertmanager&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sudo useradd --no-create-home --shell /bin/false prometheus&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;prometheus-exporter:prometheus-exporter&lt;/code&gt; for ownership of exporters. Exporters should possibly be more isolated but I feel it may be a case of YAGNI.

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sudo useradd --no-create-home --shell /bin/false prometheus-exporter&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Set scrape_interval to 1 minute: &lt;code&gt;scrape_interval: 1m&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;15 seconds is still doable but I'm currently not concerned with very granular detail.&lt;/li&gt;
&lt;li&gt;This reduces the load of making 4 calls per minute to just 1, reducing some overhead required for Prometheus and every exporter.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At $dayJob we've moved to provisioning servers using Laravel Forge, which has the possibility of utilizing exporters for mysqld, mariadb, postgres, memcached, redis, beanstalkd, nginx, php-fpm, and sendmail. I've opted to use &lt;a href="https://github.com/prometheus/node_exporter"&gt;node_exporter&lt;/a&gt;, &lt;a href="https://github.com/prometheus/mysqld_exporter"&gt;mysqld&lt;/a&gt;, &lt;a href="https://github.com/hnlq715/nginx-vts-exporter"&gt;nginx-vts-exporter&lt;/a&gt;, &lt;a href="https://github.com/hipages/php-fpm_exporter"&gt;php-fpm&lt;/a&gt;, and &lt;a href="https://github.com/oliver006/redis_exporter"&gt;redis&lt;/a&gt; respectively. To put the original premise into perspective, replicating the newer monitoring agent graphs in Digital Ocean only require &lt;code&gt;node_exporter&lt;/code&gt;. A few of the exporters require very little setup, only setting a few configuration variables systemd service definitions. Other exporters like &lt;code&gt;nginx-vts-exporter&lt;/code&gt; require building nginx from source.&lt;/p&gt;

&lt;p&gt;I plan to introduce a series of posts that should aid in getting a very rudimentary implementation running. There is an abundant usage of Kubernetes in the Prometheus ecosystem, to the point that it almost seems required but fortunately it also just works(tm) in a traditional virtual machine without any real fuss.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
