<rss xmlns:source="http://source.scripting.com/" version="2.0">
  <channel>
    <title>Gwendolyn James</title>
    <link>https://gwynforthewyn.com/</link>
    <description></description>
    
    <language>en</language>
    
    <lastBuildDate>Sun, 09 Nov 2025 20:23:17 -0700</lastBuildDate>
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/11/09/ive-been-learning-about-web.html</link>
      <pubDate>Sun, 09 Nov 2025 20:23:17 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/11/09/ive-been-learning-about-web.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been learning about web development using svelte. It&amp;rsquo;s cool wrapping my head around this stuff finally. It&amp;rsquo;s been nice having the experience of learning new debugger tools and whatnot; it&amp;rsquo;s always a combination of frustration and sudden moments of enlightenment.&lt;/p&gt;
&lt;p&gt;I spent the last week on vacation from work. I&amp;rsquo;ve been growing a decent sized piece of infrastructure at my day job for years now, and a small piece at home that I use to learn lessons and tease myself that I can go independent some day. I spent the week cleaning up old ansible and making it all uniform, really investing in justfile tasks to drive entire workflows from one tool, building out my vibe-coded small business idea, that sort of stuff.&lt;/p&gt;
&lt;p&gt;Seeing how much better it feels to have nothing in between the workflows I want to activate and my mind, that I understand every codebase really well right now, it&amp;rsquo;s such a freeing lack of friction. I improved all my build times down from 2 1/2 minutes-ish to under 30 seconds, and it feels amazing knowing I get all my feedback that rapidly.&lt;/p&gt;
&lt;p&gt;I dunno, it feels like lessons to bring over to dayjob. I always miss the feeling of my personal projects when I&amp;rsquo;m at work; I move so much more fluidly in this environment, with better tools. The degree of friction getting decisions made at work is aggravating at times: I have to work with teams that are backlogged enough that it can be weeks before a job is unblocked.&lt;/p&gt;
&lt;p&gt;I should maybe try and design our workflows to insulate us a bit more, but it feels like the wrong solution. The right solution is always going  to be to tackle friction head-on, but god damn is it tiring.&lt;/p&gt;
</description>
      <source:markdown>I&#39;ve been learning about web development using svelte. It&#39;s cool wrapping my head around this stuff finally. It&#39;s been nice having the experience of learning new debugger tools and whatnot; it&#39;s always a combination of frustration and sudden moments of enlightenment.

I spent the last week on vacation from work. I&#39;ve been growing a decent sized piece of infrastructure at my day job for years now, and a small piece at home that I use to learn lessons and tease myself that I can go independent some day. I spent the week cleaning up old ansible and making it all uniform, really investing in justfile tasks to drive entire workflows from one tool, building out my vibe-coded small business idea, that sort of stuff.

Seeing how much better it feels to have nothing in between the workflows I want to activate and my mind, that I understand every codebase really well right now, it&#39;s such a freeing lack of friction. I improved all my build times down from 2 1/2 minutes-ish to under 30 seconds, and it feels amazing knowing I get all my feedback that rapidly.

I dunno, it feels like lessons to bring over to dayjob. I always miss the feeling of my personal projects when I&#39;m at work; I move so much more fluidly in this environment, with better tools. The degree of friction getting decisions made at work is aggravating at times: I have to work with teams that are backlogged enough that it can be weeks before a job is unblocked.

I should maybe try and design our workflows to insulate us a bit more, but it feels like the wrong solution. The right solution is always going  to be to tackle friction head-on, but god damn is it tiring.
</source:markdown>
    </item>
    
    <item>
      <title>all it cost me was not writing a line of it</title>
      <link>https://gwynforthewyn.com/2025/10/19/all-it-cost-me-was.html</link>
      <pubDate>Sun, 19 Oct 2025 08:42:21 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/10/19/all-it-cost-me-was.html</guid>
      <description>&lt;h2 id=&#34;learning-has-always-been-hard&#34;&gt;Learning has always been hard&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve always found that learning a new skill takes time and effort. It helps that I normally learn things that I enjoy, but even so it&amp;rsquo;s tough to learn a little more calculus, start learning javascript, tackle learning Spanish or French.&lt;/p&gt;
&lt;p&gt;I find that letting the grind be hard, being okay with slow progress, this is a mindset game that sometimes works and sometimes doesn&amp;rsquo;t.&lt;/p&gt;
&lt;h2 id=&#34;getting-to-70-is-easy-now&#34;&gt;Getting to 70% Is Easy Now&lt;/h2&gt;
&lt;p&gt;The last time I learned a new language well enough to feel confident every day in it, it was golang.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been learning svelte recently. It&amp;rsquo;s so much harder, not because Svelte&amp;rsquo;s bad or anything but because I can ask Claude for a &amp;ldquo;code sample&amp;rdquo; and the next thing I know I&amp;rsquo;m eight commits down and have most of what I want and the part that&amp;rsquo;s left is both hard to get Claude to build and hard for my own skills to approach because I haven&amp;rsquo;t trained them.&lt;/p&gt;
&lt;h2 id=&#34;learning-is-95-doing&#34;&gt;Learning is 95% Doing&lt;/h2&gt;
&lt;p&gt;I have a tool that genuinely makes it easy to remove the &amp;ldquo;doing&amp;rdquo; part from learning a new framework. I feel like I feel when I eat cheap carbs: I know they will make me put on weight, I know that&amp;rsquo;s basically bad for me, I know they&amp;rsquo;re delicious in a way that fibrous greens aren&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;Am I putting on brain-fat? Getting brain-weak and brain-lazy? I know I&amp;rsquo;ve seen smart people, much smarter than me, who I&amp;rsquo;d charactertise today as brain-lazy because they&amp;rsquo;ve started mistaking conversations with ChatGPT for thinking through a problem, started sharing unedited conversations and trying to persuade me they&amp;rsquo;re a whitepaper.&lt;/p&gt;
&lt;h2 id=&#34;in-praise-of-a-shitty-first-draft&#34;&gt;In Praise of a Shitty First Draft&lt;/h2&gt;
&lt;p&gt;I think the book &amp;ldquo;bird by bird&amp;rdquo; is the one that contains the &amp;ldquo;In praise of a shitty first draft&amp;rdquo; essay. It talks you through acknowledging internally that writing something good isn&amp;rsquo;t the hard part, it&amp;rsquo;s finishing anything at all. The productivity people seem to get to the same idea: you should lower your standards for your first attempt because it&amp;rsquo;s hard enough just to finish.&lt;/p&gt;
&lt;p&gt;My first attempt at a sveltekit app works and does 70% of what I want 70% of the time, and all it cost me was that I didn&amp;rsquo;t write a line of it. That last 30% is a hard wall to climb when my skills haven&amp;rsquo;t been developed.&lt;/p&gt;
&lt;p&gt;My skills haven&amp;rsquo;t been developed. They&amp;rsquo;re not developing when I let Claude prototype and prototype until I stop.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m seeing how to get brain-obese, and I&amp;rsquo;m watching opinions on that obesity evolve in our community.&lt;/p&gt;
&lt;p&gt;Remember the first time you saw the Chauncey Morlan photo, the 1890s circus dude who was billed as the heaviest man on the planet, and you thought to yourself &amp;ldquo;damn, I see people bigger than that on the street these days&amp;rdquo;? We&amp;rsquo;re used to living our lives obese, seeing obese neighbours and coworkers, feeling uncomfortable without knowing how much better it can be.&lt;/p&gt;
&lt;p&gt;Our brains, our minds, we can get comfortable with this shitty normalisation there too. You see people now who argue not only that never-before seen levels of obesity are perfectly ordinary, they&amp;rsquo;re latching on to interesting ideas like the aquatic ape and twisting it into explanations of humanity to make the argument that the non-obese are the problem, the unusual ones historically.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll get used to people not completing thoughts, not being able to complete thoughts, not able to design an end to end workflow, not thinking through problems. We&amp;rsquo;re already letting ourselves have Claude write the code, have Claude and CoPilot perform the code review, have them resolve their own meaningless observations, chase their own tails.&lt;/p&gt;
&lt;h2 id=&#34;or-just-maybe-im-getting-old&#34;&gt;Or, just maybe I&amp;rsquo;m getting old&lt;/h2&gt;
&lt;p&gt;The fear I have here is remembering the headlines of a hundred, two hundred years ago. Vicemius Knox must surely have felt fear when he wrote &amp;ldquo;If it is true, that the present age is more corrupt than the preceding, the great multiplication of Novels probably contributes to its degeneracy.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Am I being scared by a change in behaviour that&amp;rsquo;ll basically all come out in the wash? Hard to say, hard to say, hard to say. Maybe society changes, maybe some people do stop being able to write code using some approaches that I think have merit. Who am I to say what approaches have merit, though? Surely Linus or Kate or my friend Doug would all look at what I write and recognise that I&amp;rsquo;m barely software literate.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s all so much to take in.&lt;/p&gt;
</description>
      <source:markdown>## Learning has always been hard
I&#39;ve always found that learning a new skill takes time and effort. It helps that I normally learn things that I enjoy, but even so it&#39;s tough to learn a little more calculus, start learning javascript, tackle learning Spanish or French.

I find that letting the grind be hard, being okay with slow progress, this is a mindset game that sometimes works and sometimes doesn&#39;t.

## Getting to 70% Is Easy Now
The last time I learned a new language well enough to feel confident every day in it, it was golang. 

I&#39;ve been learning svelte recently. It&#39;s so much harder, not because Svelte&#39;s bad or anything but because I can ask Claude for a &#34;code sample&#34; and the next thing I know I&#39;m eight commits down and have most of what I want and the part that&#39;s left is both hard to get Claude to build and hard for my own skills to approach because I haven&#39;t trained them.

## Learning is 95% Doing
I have a tool that genuinely makes it easy to remove the &#34;doing&#34; part from learning a new framework. I feel like I feel when I eat cheap carbs: I know they will make me put on weight, I know that&#39;s basically bad for me, I know they&#39;re delicious in a way that fibrous greens aren&#39;t.

Am I putting on brain-fat? Getting brain-weak and brain-lazy? I know I&#39;ve seen smart people, much smarter than me, who I&#39;d charactertise today as brain-lazy because they&#39;ve started mistaking conversations with ChatGPT for thinking through a problem, started sharing unedited conversations and trying to persuade me they&#39;re a whitepaper.

## In Praise of a Shitty First Draft
I think the book &#34;bird by bird&#34; is the one that contains the &#34;In praise of a shitty first draft&#34; essay. It talks you through acknowledging internally that writing something good isn&#39;t the hard part, it&#39;s finishing anything at all. The productivity people seem to get to the same idea: you should lower your standards for your first attempt because it&#39;s hard enough just to finish.

My first attempt at a sveltekit app works and does 70% of what I want 70% of the time, and all it cost me was that I didn&#39;t write a line of it. That last 30% is a hard wall to climb when my skills haven&#39;t been developed.

My skills haven&#39;t been developed. They&#39;re not developing when I let Claude prototype and prototype until I stop.

I&#39;m seeing how to get brain-obese, and I&#39;m watching opinions on that obesity evolve in our community.

Remember the first time you saw the Chauncey Morlan photo, the 1890s circus dude who was billed as the heaviest man on the planet, and you thought to yourself &#34;damn, I see people bigger than that on the street these days&#34;? We&#39;re used to living our lives obese, seeing obese neighbours and coworkers, feeling uncomfortable without knowing how much better it can be.

Our brains, our minds, we can get comfortable with this shitty normalisation there too. You see people now who argue not only that never-before seen levels of obesity are perfectly ordinary, they&#39;re latching on to interesting ideas like the aquatic ape and twisting it into explanations of humanity to make the argument that the non-obese are the problem, the unusual ones historically. 

We&#39;ll get used to people not completing thoughts, not being able to complete thoughts, not able to design an end to end workflow, not thinking through problems. We&#39;re already letting ourselves have Claude write the code, have Claude and CoPilot perform the code review, have them resolve their own meaningless observations, chase their own tails.

## Or, just maybe I&#39;m getting old
The fear I have here is remembering the headlines of a hundred, two hundred years ago. Vicemius Knox must surely have felt fear when he wrote &#34;If it is true, that the present age is more corrupt than the preceding, the great multiplication of Novels probably contributes to its degeneracy.&#34;

Am I being scared by a change in behaviour that&#39;ll basically all come out in the wash? Hard to say, hard to say, hard to say. Maybe society changes, maybe some people do stop being able to write code using some approaches that I think have merit. Who am I to say what approaches have merit, though? Surely Linus or Kate or my friend Doug would all look at what I write and recognise that I&#39;m barely software literate.

It&#39;s all so much to take in.
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/27/as-a-follow-up-to.html</link>
      <pubDate>Mon, 27 Jan 2025 21:12:10 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/27/as-a-follow-up-to.html</guid>
      <description>&lt;p&gt;As a follow up to my last post on &lt;a href=&#34;https://gwynforthewyn.com/2025/01/24/how-does-charm-logger-format.html&#34;&gt;Charm&amp;rsquo;s Logger package&lt;/a&gt;, I took a look at memory usage for a predefined logLevel, a raw int 100, and math.MaxInt32. My hypothesis was that math.MaxInt32 is more efficient, but using math.MaxInt32, there were &lt;em&gt;no&lt;/em&gt; memory allocations shown by the profiler. Amazing!&lt;/p&gt;
</description>
      <source:markdown>As a follow up to my last post on [Charm&#39;s Logger package](https://gwynforthewyn.com/2025/01/24/how-does-charm-logger-format.html ), I took a look at memory usage for a predefined logLevel, a raw int 100, and math.MaxInt32. My hypothesis was that math.MaxInt32 is more efficient, but using math.MaxInt32, there were _no_ memory allocations shown by the profiler. Amazing!
</source:markdown>
    </item>
    
    <item>
      <title>How Does Charm Logger Format Logs?</title>
      <link>https://gwynforthewyn.com/2025/01/24/how-does-charm-logger-format.html</link>
      <pubDate>Fri, 24 Jan 2025 07:23:43 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/24/how-does-charm-logger-format.html</guid>
      <description>&lt;p&gt;I woke up today wondering how charm&amp;rsquo;s logger library (&lt;a href=&#34;https://github.com/charmbracelet/log&#34;&gt;https://github.com/charmbracelet/log&lt;/a&gt;) actually handles log levels. I know they have some levels predefined in an enum, but what&amp;rsquo;re they doing with that? This is relevant to #golang #opensource #programming #readingcode&lt;/p&gt;
&lt;p&gt;logger.Log is the natural entrypoint, as it&amp;rsquo;s the actual code doing the logging &lt;a href=&#34;https://github.com/charmbracelet/log/blob/1e6353e3ca793f1177148e09f990ef220e19b037/logger.go#L56&#34;&gt;https://github.com/charmbracelet/log/blob/1e6353e3ca793f1177148e09f990ef220e19b037/logger.go#L56&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It dispatches to logger.handle, which has this curious setup:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Logger&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;handle&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;level&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Level&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ts&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Time&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;frames&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;runtime&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Frame&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}, &lt;span style=&#34;color:#a6e22e&#34;&gt;keyvals&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}) {

	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;kvs&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}
	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;reportTimestamp&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; !&lt;span style=&#34;color:#a6e22e&#34;&gt;ts&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;IsZero&lt;/span&gt;() {
		&lt;span style=&#34;color:#a6e22e&#34;&gt;kvs&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;kvs&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;TimestampKey&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ts&lt;/span&gt;)
	}

	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;level&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;noLevel&lt;/span&gt; {
		&lt;span style=&#34;color:#a6e22e&#34;&gt;kvs&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;kvs&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;LevelKey&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;level&lt;/span&gt;)
	}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I think this means that no matter your log level, whether the log will print or not, the logger &lt;em&gt;always&lt;/em&gt; constructs a log line for you, unless you match the noLevel?&lt;/p&gt;
&lt;p&gt;As a note, noLevel is private, but is defined as &lt;code&gt;math.MaxInt32&lt;/code&gt;. This probably means the most efficient way to generate no logs is to declare your own equivalent &lt;code&gt;noLog&lt;/code&gt; level as a default, but I can come back to that in a few paragraphs.&lt;/p&gt;
&lt;p&gt;So how do the logs get written? Scanning to the end of the function, it&amp;rsquo;s this straightforwards &lt;code&gt;l.b.WriteTo(l.w)&lt;/code&gt;. l is a pointer to the logger struct, b is a bytes.buffer inside that logger, and it&amp;rsquo;s written out to whatever destination is stored in an io.writer called &lt;code&gt;w&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So if we can understand how  &lt;code&gt;b&lt;/code&gt; get populated, we&amp;rsquo;ve cracked how these logs are written. The answer is in this switch statement, though it&amp;rsquo;s indirect:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;formatter&lt;/span&gt; {
	&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;LogfmtFormatter&lt;/span&gt;:
		&lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;logfmtFormatter&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;kvs&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)
	&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSONFormatter&lt;/span&gt;:
		&lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;jsonFormatter&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;kvs&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)
	&lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;:
		&lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;textFormatter&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;kvs&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each of these formatters accepts responsibility for populating the buffer with an appropriately formatted log output. The logfmtFormatter, for example, begins with &lt;code&gt;e := logfmt.NewEncoder(&amp;amp;l.b)&lt;/code&gt;, accepting a reference to the buffer.&lt;/p&gt;
&lt;p&gt;So, that&amp;rsquo;s the story. Logs are appended to a key value store, which is handed to a formatter that writes formatted output to a buffer on the logger, which is then written.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll come back to the question of figuring out if the best performing no-opt logger is setting hte logLevel to &lt;code&gt;math.MaxInt32&lt;/code&gt; in my next post about this.&lt;/p&gt;
</description>
      <source:markdown>I woke up today wondering how charm&#39;s logger library (https://github.com/charmbracelet/log) actually handles log levels. I know they have some levels predefined in an enum, but what&#39;re they doing with that? This is relevant to #golang #opensource #programming #readingcode

logger.Log is the natural entrypoint, as it&#39;s the actual code doing the logging https://github.com/charmbracelet/log/blob/1e6353e3ca793f1177148e09f990ef220e19b037/logger.go#L56

It dispatches to logger.handle, which has this curious setup:

```go
func (l *Logger) handle(level Level, ts time.Time, frames []runtime.Frame, msg interface{}, keyvals ...interface{}) {

	var kvs []interface{}
	if l.reportTimestamp &amp;&amp; !ts.IsZero() {
		kvs = append(kvs, TimestampKey, ts)
	}

	if level != noLevel {
		kvs = append(kvs, LevelKey, level)
	}
```

I think this means that no matter your log level, whether the log will print or not, the logger _always_ constructs a log line for you, unless you match the noLevel?

As a note, noLevel is private, but is defined as `math.MaxInt32`. This probably means the most efficient way to generate no logs is to declare your own equivalent `noLog` level as a default, but I can come back to that in a few paragraphs.

So how do the logs get written? Scanning to the end of the function, it&#39;s this straightforwards `l.b.WriteTo(l.w)`. l is a pointer to the logger struct, b is a bytes.buffer inside that logger, and it&#39;s written out to whatever destination is stored in an io.writer called `w`.

So if we can understand how  `b` get populated, we&#39;ve cracked how these logs are written. The answer is in this switch statement, though it&#39;s indirect:

```go
	switch l.formatter {
	case LogfmtFormatter:
		l.logfmtFormatter(kvs...)
	case JSONFormatter:
		l.jsonFormatter(kvs...)
	default:
		l.textFormatter(kvs...)
```
Each of these formatters accepts responsibility for populating the buffer with an appropriately formatted log output. The logfmtFormatter, for example, begins with `e := logfmt.NewEncoder(&amp;l.b)`, accepting a reference to the buffer.

So, that&#39;s the story. Logs are appended to a key value store, which is handed to a formatter that writes formatted output to a buffer on the logger, which is then written.

I&#39;ll come back to the question of figuring out if the best performing no-opt logger is setting hte logLevel to `math.MaxInt32` in my next post about this.


</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/19/time-to-update-my-logo.html</link>
      <pubDate>Sun, 19 Jan 2025 08:48:12 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/19/time-to-update-my-logo.html</guid>
      <description>&lt;p&gt;Time to update my logo. &lt;code&gt;find . -iname &amp;quot;*.html&amp;quot; -exec sed -i &#39;&#39; &#39;s/logo.png/dolphint.png/&#39; {} \;&lt;/code&gt; 
I never did fall in love with xargs.&lt;/p&gt;
</description>
      <source:markdown>Time to update my logo. `find . -iname &#34;*.html&#34; -exec sed -i &#39;&#39; &#39;s/logo.png/dolphint.png/&#39; {} \;` 
I never did fall in love with xargs.
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/19/the-joy-of-maintaining-a.html</link>
      <pubDate>Sun, 19 Jan 2025 08:44:51 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/19/the-joy-of-maintaining-a.html</guid>
      <description>&lt;p&gt;The joy of maintaining a website as flat files is mostly found in using &lt;code&gt;sed&lt;/code&gt; for sitewide refactoring.&lt;/p&gt;
</description>
      <source:markdown>The joy of maintaining a website as flat files is mostly found in using `sed` for sitewide refactoring.

</source:markdown>
    </item>
    
    <item>
      <title>two goals today</title>
      <link>https://gwynforthewyn.com/2025/01/19/two-goals-today.html</link>
      <pubDate>Sun, 19 Jan 2025 08:17:46 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/19/two-goals-today.html</guid>
      <description>&lt;p&gt;My first goal today is to look at PlayTechnique&amp;rsquo;s website, simplify the front page to a clearer &amp;ldquo;this could be a business you trust&amp;rdquo; message, and figure out what layout works for the combination of blog posts and project docs that&amp;rsquo;re on there.&lt;/p&gt;
&lt;p&gt;My second goal is to begin the Jinx rewrite I&amp;rsquo;ve been avoiding for a year. Jinx is such a great workflow for dockerised Jenkins, it&amp;rsquo;s a shame not to finish it up and get it released. I want it to meet my original goal of &lt;code&gt;rails&lt;/code&gt;-like cli for Jenkins containers.&lt;/p&gt;
</description>
      <source:markdown>My first goal today is to look at PlayTechnique&#39;s website, simplify the front page to a clearer &#34;this could be a business you trust&#34; message, and figure out what layout works for the combination of blog posts and project docs that&#39;re on there.

My second goal is to begin the Jinx rewrite I&#39;ve been avoiding for a year. Jinx is such a great workflow for dockerised Jenkins, it&#39;s a shame not to finish it up and get it released. I want it to meet my original goal of `rails`-like cli for Jenkins containers.
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/19/the-scary-thing-in-my.html</link>
      <pubDate>Sun, 19 Jan 2025 08:11:47 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/19/the-scary-thing-in-my.html</guid>
      <description>&lt;p&gt;The scary thing in my heart is holding simultaneously knowledge that I am a productive, ordinary person with minor ambitions, and that the legislators of the country are okay legally redefining me as a terrifying monster.&lt;/p&gt;
</description>
      <source:markdown>The scary thing in my heart is holding simultaneously knowledge that I am a productive, ordinary person with minor ambitions, and that the legislators of the country are okay legally redefining me as a terrifying monster. 
 
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/18/i-was-sad-to-find.html</link>
      <pubDate>Sat, 18 Jan 2025 11:14:35 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/18/i-was-sad-to-find.html</guid>
      <description>&lt;p&gt;I was sad to find out that Hey email doesn&amp;rsquo;t support being an SMTP relay. The UI&amp;rsquo;s really quite nice, but I have a few alerts I need to forward, so it&amp;rsquo;s on to the next big thing.&lt;/p&gt;
</description>
      <source:markdown>I was sad to find out that Hey email doesn&#39;t support being an SMTP relay. The UI&#39;s really quite nice, but I have a few alerts I need to forward, so it&#39;s on to the next big thing. 
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/14/every-day-i-remember-my.html</link>
      <pubDate>Tue, 14 Jan 2025 07:49:06 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/14/every-day-i-remember-my.html</guid>
      <description>&lt;p&gt;Every day I remember my Productive Days and think &amp;ldquo;I should get an early start on work, because Productive feels Good&amp;rdquo; and every morning I sit here reading a little book or codebase unrelated to work and feel joy instead of the productive good.&lt;/p&gt;
</description>
      <source:markdown>Every day I remember my Productive Days and think &#34;I should get an early start on work, because Productive feels Good&#34; and every morning I sit here reading a little book or codebase unrelated to work and feel joy instead of the productive good.
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/14/damn-i-wish-id-written.html</link>
      <pubDate>Tue, 14 Jan 2025 07:44:38 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/14/damn-i-wish-id-written.html</guid>
      <description>&lt;p&gt;Damn I wish I&amp;rsquo;d written this - &lt;a href=&#34;https://github.com/esnet/gdg.&#34;&gt;github.com/esnet/gdg&amp;hellip;&lt;/a&gt; It&amp;rsquo;s a CLI tool for grabbing grafana dashboards from your instance. I want to take a day off to read it and learn. It uses mockery, Taskfiles, a VHS tape (I haven&amp;rsquo;t used VHS since rails!), go-releaser. A joyful tool romp!&lt;/p&gt;
</description>
      <source:markdown>Damn I wish I&#39;d written this - [github.com/esnet/gdg...](https://github.com/esnet/gdg.) It&#39;s a CLI tool for grabbing grafana dashboards from your instance. I want to take a day off to read it and learn. It uses mockery, Taskfiles, a VHS tape (I haven&#39;t used VHS since rails!), go-releaser. A joyful tool romp!
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/13/i-started-watching-videos-on.html</link>
      <pubDate>Mon, 13 Jan 2025 07:07:27 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/13/i-started-watching-videos-on.html</guid>
      <description>&lt;p&gt;I started watching videos on prompt engineering yesterday. So far I&amp;rsquo;m thirty minutes in and it feels like a scam. I keep thinking from reading Simon Williamson&amp;rsquo;s blog that there&amp;rsquo;s utility to understanding the models when crafting prompts, but gosh darn it more feels like a prose writing course.&lt;/p&gt;
</description>
      <source:markdown>I started watching videos on prompt engineering yesterday. So far I&#39;m thirty minutes in and it feels like a scam. I keep thinking from reading Simon Williamson&#39;s blog that there&#39;s utility to understanding the models when crafting prompts, but gosh darn it more feels like a prose writing course.
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/09/its-a-small-thing-but.html</link>
      <pubDate>Thu, 09 Jan 2025 22:46:46 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/09/its-a-small-thing-but.html</guid>
      <description>&lt;p&gt;It’s a small thing but this evening I understand the permission in a browser extension’s manifest a bit better than this morning, and the errors caused by incorrect permissions, and that’s progress and that’s enough.&lt;/p&gt;
</description>
      <source:markdown>It’s a small thing but this evening I understand the permission in a browser extension’s manifest a bit better than this morning, and the errors caused by incorrect permissions, and that’s progress and that’s enough. 
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/09/yay-i-said-now-we.html</link>
      <pubDate>Thu, 09 Jan 2025 07:15:30 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/09/yay-i-said-now-we.html</guid>
      <description>&lt;p&gt;Yay, I said, now we have a log ingester and this is great! But one who had been here before said no, now our troubles begin for now we have to learn yet another unique query language.&lt;/p&gt;
</description>
      <source:markdown>Yay, I said, now we have a log ingester and this is great! But one who had been here before said no, now our troubles begin for now we have to learn yet another unique query language. 
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/07/i-found-a-neat-cli.html</link>
      <pubDate>Tue, 07 Jan 2025 18:43:35 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/07/i-found-a-neat-cli.html</guid>
      <description>&lt;p&gt;I found a neat CLI tool today. Check out &lt;code&gt;man comm&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;comm – select or reject lines common to two files&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Try it out! &lt;code&gt;ls &amp;gt; 1.txt &amp;amp;&amp;amp; ls | sed &#39;$d&#39; &amp;gt; 2.txt &amp;amp;&amp;amp; comm 1.txt 2.txt&lt;/code&gt;&lt;/p&gt;
</description>
      <source:markdown>I found a neat CLI tool today. Check out `man comm`

&gt; comm – select or reject lines common to two files

Try it out! `ls &gt; 1.txt &amp;&amp; ls | sed &#39;$d&#39; &gt; 2.txt &amp;&amp; comm 1.txt 2.txt`
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/07/what-an-interesting-way-to.html</link>
      <pubDate>Tue, 07 Jan 2025 18:39:58 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/07/what-an-interesting-way-to.html</guid>
      <description>&lt;p&gt;What an interesting way to discover I can&amp;rsquo;t write an html tag directly in micro.blog. &lt;code&gt;&amp;lt;/rss&amp;gt;&lt;/code&gt; was the missing tag, for all nobody who wondered.&lt;/p&gt;
</description>
      <source:markdown>What an interesting way to discover I can&#39;t write an html tag directly in micro.blog. `&lt;/rss&gt;` was the missing tag, for all nobody who wondered.
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/07/fixed-the-rss-feed-in.html</link>
      <pubDate>Tue, 07 Jan 2025 18:28:32 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/07/fixed-the-rss-feed-in.html</guid>
      <description>&lt;p&gt;Fixed the rss feed in Andrew. It turned out I was missing a &lt;/rss&gt;. How simple a fix!&lt;/p&gt;
</description>
      <source:markdown>Fixed the rss feed in Andrew. It turned out I was missing a &lt;/rss&gt;. How simple a fix!
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/07/im-not-sure-if-microblog.html</link>
      <pubDate>Tue, 07 Jan 2025 17:17:59 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/07/im-not-sure-if-microblog.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;m not sure if micro.blog is replacing my quotes with smart quotes, or if it&amp;rsquo;s something else in the stack. Truly it was irritating when it came to copy/paste my code this morning.&lt;/p&gt;
</description>
      <source:markdown>I&#39;m not sure if micro.blog is replacing my quotes with smart quotes, or if it&#39;s something else in the stack. Truly it was irritating when it came to copy/paste my code this morning.
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/07/two-projects-today-fix-the.html</link>
      <pubDate>Tue, 07 Jan 2025 08:29:05 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/07/two-projects-today-fix-the.html</guid>
      <description>&lt;p&gt;Two projects today: fix the rss feed for Andrew, and put together yesterday&amp;rsquo;s #fluentbit investigations as a wee go program. First, I should decide if my headache is mellow enough to go back to work.&lt;/p&gt;
</description>
      <source:markdown>Two projects today: fix the rss feed for Andrew, and put together yesterday&#39;s #fluentbit investigations as a wee go program. First, I should decide if my headache is mellow enough to go back to work.
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/06/moving-on-from-source-codem.html</link>
      <pubDate>Mon, 06 Jan 2025 13:49:29 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/06/moving-on-from-source-codem.html</guid>
      <description>&lt;p&gt;Moving on from source codem, here&amp;rsquo;s the log paths reconstructed:
; k get pods &amp;ndash;all-namespaces -o json | jq -r &amp;lsquo;.items[] | .metadata.name + &amp;ldquo;&lt;em&gt;&amp;rdquo; + .metadata.namespace + &amp;ldquo;&lt;/em&gt;&amp;rdquo; + (.spec.containers[].name) + &amp;ldquo;-&amp;rdquo; + (.status.containerStatuses[].containerID | split(&amp;quot;://&amp;quot;)[1]) + &amp;ldquo;.log&amp;rdquo;&amp;rsquo;&lt;/p&gt;
</description>
      <source:markdown>Moving on from source codem, here&#39;s the log paths reconstructed:
; k get pods --all-namespaces -o json | jq -r &#39;.items[] | .metadata.name + &#34;_&#34; + .metadata.namespace + &#34;_&#34; + (.spec.containers[].name) + &#34;-&#34; + (.status.containerStatuses[].containerID | split(&#34;://&#34;)[1]) + &#34;.log&#34;&#39;

</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/06/ah-the-legacy-pattern-doesnt.html</link>
      <pubDate>Mon, 06 Jan 2025 13:43:22 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/06/ah-the-legacy-pattern-doesnt.html</guid>
      <description>&lt;p&gt;Ah, the legacy pattern doesn&amp;rsquo;t contain the namespace. I wonder if that&amp;rsquo;s why it&amp;rsquo;s legacy&amp;hellip;&lt;/p&gt;
&lt;p&gt;The legacy tests &lt;em&gt;do&lt;/em&gt; include the namespace. Odd &lt;a href=&#34;https://github.com/kubernetes/kubernetes/blob/c3f3fdc1aa62002a58bec1141fe69e86bbb27491/pkg/kubelet/kuberuntime/legacy_test.go#L56&#34;&gt;github.com/kubernete&amp;hellip;&lt;/a&gt;&lt;/p&gt;
</description>
      <source:markdown>Ah, the legacy pattern doesn&#39;t contain the namespace. I wonder if that&#39;s why it&#39;s legacy...

The legacy tests _do_ include the namespace. Odd [github.com/kubernete...](https://github.com/kubernetes/kubernetes/blob/c3f3fdc1aa62002a58bec1141fe69e86bbb27491/pkg/kubelet/kuberuntime/legacy_test.go#L56)
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/06/i-as-close-this-seems.html</link>
      <pubDate>Mon, 06 Jan 2025 13:32:56 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/06/i-as-close-this-seems.html</guid>
      <description>&lt;p&gt;I as close! This seems like a good enough reference for the log path &lt;a href=&#34;https://github.com/kubernetes/kubernetes/blob/b7ef173c59065f9a5f68eb514ef0483c6f3887ae/pkg/kubelet/kuberuntime/legacy.go#L69&#34;&gt;github.com/kubernete&amp;hellip;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;logPath := fmt.Sprintf(&amp;quot;%s_%s-%s&amp;quot;, podFullName, containerName, containerID)&lt;/p&gt;
</description>
      <source:markdown>I as close! This seems like a good enough reference for the log path [github.com/kubernete...](https://github.com/kubernetes/kubernetes/blob/b7ef173c59065f9a5f68eb514ef0483c6f3887ae/pkg/kubelet/kuberuntime/legacy.go#L69)

logPath := fmt.Sprintf(&#34;%s_%s-%s&#34;, podFullName, containerName, containerID)

</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/06/when-fluentbit-retrieves-logs-its.html</link>
      <pubDate>Mon, 06 Jan 2025 13:21:20 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/06/when-fluentbit-retrieves-logs-its.html</guid>
      <description>&lt;p&gt;When fluentbit retrieves logs, it&amp;rsquo;s worth knowing two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It gets container logs, not pod logs&lt;/li&gt;
&lt;li&gt;dockerd arranges for a container&amp;rsquo;s name in the log file to be podName_namespace_imageName-dockerdContainerID&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I assume different container daemons might give &amp;lsquo;em different names. I&amp;rsquo;ll check&amp;hellip;&lt;/p&gt;
</description>
      <source:markdown>When fluentbit retrieves logs, it&#39;s worth knowing two things:

1. It gets container logs, not pod logs
2. dockerd arranges for a container&#39;s name in the log file to be podName_namespace_imageName-dockerdContainerID

I assume different container daemons might give &#39;em different names. I&#39;ll check...
</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/06/the-answer-was-to-ask.html</link>
      <pubDate>Mon, 06 Jan 2025 13:12:59 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/06/the-answer-was-to-ask.html</guid>
      <description>&lt;p&gt;The answer was to ask ChatGPT to solve the question for me:&lt;/p&gt;
&lt;p&gt;; kubectl get pods &amp;ndash;all-namespaces -o jsonpath=&amp;quot;{range .items[&lt;em&gt;]}{.spec.containers[&lt;/em&gt;].name}{&#39;\n&#39;}{end}&amp;quot;&lt;/p&gt;
</description>
      <source:markdown>The answer was to ask ChatGPT to solve the question for me:

; kubectl get pods --all-namespaces -o jsonpath=&#34;{range .items[*]}{.spec.containers[*].name}{&#39;\n&#39;}{end}&#34;

</source:markdown>
    </item>
    
    <item>
      <title></title>
      <link>https://gwynforthewyn.com/2025/01/06/a-few-minutes-later-ive.html</link>
      <pubDate>Mon, 06 Jan 2025 13:08:48 -0700</pubDate>
      
      <guid>http://gwynforthewyn.micro.blog/2025/01/06/a-few-minutes-later-ive.html</guid>
      <description>&lt;p&gt;A few minutes later I&amp;rsquo;ve edited the configmap for fluentbit and restarted the pod. The fluentbit logs now show this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[error] [input:tail:tail.0] read error, check permissions: /var/log/justnocontainers/*.log&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Okay, so what&amp;rsquo;s the quickest way to see all the actual containers using kubectl&amp;hellip;&lt;/p&gt;
</description>
      <source:markdown>A few minutes later I&#39;ve edited the configmap for fluentbit and restarted the pod. The fluentbit logs now show this:

&gt; [error] [input:tail:tail.0] read error, check permissions: /var/log/justnocontainers/*.log

Okay, so what&#39;s the quickest way to see all the actual containers using kubectl...
</source:markdown>
    </item>
    
  </channel>
</rss>
