<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title> - Miscellaneous</title>
		<description>Posts tags as 'python'</description>
		<link>https://fruch.github.io</link>
		<atom:link href="https://fruch.github.io/feed.python.xml" rel="self" type="application/rss+xml" />
		
			<item>
				<title>Maybe ORM/ODM are not dead? Yet...</title>
				<description>
&lt;p&gt;So, let’s pick up where we left off. A couple of weeks ago, I wrote about how I took a 4-year-old fever dream—an ODM for Cassandra and ScyllaDB called &lt;a href=&quot;https://github.com/fruch/coodie&quot;&gt;coodie&lt;/a&gt;—and let an AI build the whole thing while I sipped my morning coffee.&lt;/p&gt;

&lt;p&gt;It was a fun experiment. But then, a funny coincidence happened (or maybe the algorithm just has a sick sense of humor).&lt;/p&gt;

&lt;p&gt;Right after I hit publish and started feeling good about my newfound “prompt engineer” status, I was listening to an episode of the &lt;a href=&quot;https://pythonbytes.fm&quot;&gt;pythonbytes podcast&lt;/a&gt; discussing Michael Kennedy’s recent post, &lt;a href=&quot;https://blog.michaelckennedy.net&quot;&gt;Raw+DC: The ORM pattern of 2026?&lt;/a&gt;. The overarching thesis of their discussion? ORMs and ODMs are fundamentally dead. They are a relic of the past, bloated, abstraction-heavy, and ultimately, absolute performance killers.&lt;/p&gt;

&lt;p&gt;I actually fired off a Twitter thread in response to it. And honestly, at first, I had to concede. They make a really good point. I spend my days deep in the ScyllaDB trenches, where we fight for every single microsecond. Putting a thick Python abstraction layer on top of a highly optimized driver usually sounds like a brilliant way to turn a sports car into a tractor.&lt;/p&gt;

&lt;p&gt;But it got me thinking. How bad was coodie? Was my AI-generated Beanie-wannabe actually a performance disaster waiting to happen?&lt;/p&gt;

&lt;h2 id=&quot;giving-it-a-test-run&quot;&gt;Giving it a test run&lt;/h2&gt;

&lt;p&gt;Like any respectable developer looking for an excuse to avoid real work, I decided to put my money where my AI-generated mouth is. Instead of sitting at my desk, I just offloaded the whole task to the Copilot agent from my phone to run some extensive benchmarks.&lt;/p&gt;

&lt;p&gt;I didn’t just want to compare coodie to existing solutions like &lt;a href=&quot;https://docs.datastax.com/en/developer/python-driver/latest/cqlengine/&quot;&gt;cqlengine&lt;/a&gt;. I wanted to establish an absolute performance floor. I wanted to test it against the Raw+DC pattern (Python dataclasses + hand-written CQL with prepared statements) to see exactly how much the “ORM tax” was really costing us.&lt;/p&gt;

&lt;p&gt;The test spun up a local ScyllaDB node, hammered it with various workloads—inserts, reads, conditional updates, batch operations—and fetched the results back.&lt;/p&gt;

&lt;h2 id=&quot;the-finally-surprising-results&quot;&gt;The finally surprising results&lt;/h2&gt;

&lt;p&gt;I had the agent run the script. I fully expected coodie to be heavily penalized. We all accept slower performance in exchange for autocomplete, declarative schemas, and not writing raw CQL strings.&lt;/p&gt;

&lt;p&gt;I stared at the results the agent sent back to my screen. Then I told it to clear the cache, restart the Scylla container, and run it again just to be sure.&lt;/p&gt;

&lt;p&gt;The results were genuinely surprising, and running them actually highlighted a few spots where we could squeeze out even more performance, leading straight to &lt;a href=&quot;https://github.com/fruch/coodie/pull/190&quot;&gt;PR #190&lt;/a&gt; to apply those lessons learned.&lt;/p&gt;

&lt;p&gt;Here is the breakdown of what the agent and I found across the board.&lt;/p&gt;

&lt;h3 id=&quot;three-way-benchmark-results-scylla-driver&quot;&gt;Three-way Benchmark Results (scylla driver)&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Benchmark&lt;/th&gt;
      &lt;th&gt;Raw+DC (µs)&lt;/th&gt;
      &lt;th&gt;coodie (µs)&lt;/th&gt;
      &lt;th&gt;cqlengine (µs)&lt;/th&gt;
      &lt;th&gt;coodie vs Raw+DC&lt;/th&gt;
      &lt;th&gt;coodie vs cqlengine&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;single-insert&lt;/td&gt;
      &lt;td&gt;456&lt;/td&gt;
      &lt;td&gt;485&lt;/td&gt;
      &lt;td&gt;615&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1.06×&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;0.79× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;insert-if-not-exists&lt;/td&gt;
      &lt;td&gt;1,180&lt;/td&gt;
      &lt;td&gt;1,170&lt;/td&gt;
      &lt;td&gt;1,370&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;~1.00×&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;0.85× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;insert-with-ttl&lt;/td&gt;
      &lt;td&gt;448&lt;/td&gt;
      &lt;td&gt;469&lt;/td&gt;
      &lt;td&gt;640&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1.05×&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;0.73× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;get-by-pk&lt;/td&gt;
      &lt;td&gt;461&lt;/td&gt;
      &lt;td&gt;520&lt;/td&gt;
      &lt;td&gt;665&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1.13×&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;0.78× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;filter-secondary-index&lt;/td&gt;
      &lt;td&gt;1,370&lt;/td&gt;
      &lt;td&gt;2,740&lt;/td&gt;
      &lt;td&gt;8,530&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;2.00×&lt;/strong&gt; 🟠&lt;/td&gt;
      &lt;td&gt;0.32× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;filter-limit&lt;/td&gt;
      &lt;td&gt;575&lt;/td&gt;
      &lt;td&gt;627&lt;/td&gt;
      &lt;td&gt;1,220&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1.09×&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;0.51× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;count&lt;/td&gt;
      &lt;td&gt;904&lt;/td&gt;
      &lt;td&gt;1,500&lt;/td&gt;
      &lt;td&gt;1,590&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1.66×&lt;/strong&gt; 🟡&lt;/td&gt;
      &lt;td&gt;0.94× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;partial-update&lt;/td&gt;
      &lt;td&gt;409&lt;/td&gt;
      &lt;td&gt;960&lt;/td&gt;
      &lt;td&gt;542&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;2.35×&lt;/strong&gt; 🔴&lt;/td&gt;
      &lt;td&gt;1.77× ❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;update-if-condition (LWT)&lt;/td&gt;
      &lt;td&gt;1,140&lt;/td&gt;
      &lt;td&gt;1,620&lt;/td&gt;
      &lt;td&gt;1,340&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1.42×&lt;/strong&gt; 🟡&lt;/td&gt;
      &lt;td&gt;1.21× ❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;single-delete&lt;/td&gt;
      &lt;td&gt;941&lt;/td&gt;
      &lt;td&gt;925&lt;/td&gt;
      &lt;td&gt;1,190&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;~1.00×&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;0.78× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;bulk-delete&lt;/td&gt;
      &lt;td&gt;872&lt;/td&gt;
      &lt;td&gt;921&lt;/td&gt;
      &lt;td&gt;1,200&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1.06×&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;0.77× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;batch-insert-10&lt;/td&gt;
      &lt;td&gt;596&lt;/td&gt;
      &lt;td&gt;634&lt;/td&gt;
      &lt;td&gt;1,700&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1.06×&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;0.37× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;batch-insert-100&lt;/td&gt;
      &lt;td&gt;42,800&lt;/td&gt;
      &lt;td&gt;1,960&lt;/td&gt;
      &lt;td&gt;52,900&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;0.05× 🚀&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;0.04× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;collection-write&lt;/td&gt;
      &lt;td&gt;448&lt;/td&gt;
      &lt;td&gt;485&lt;/td&gt;
      &lt;td&gt;679&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1.08×&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;0.71× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;collection-read&lt;/td&gt;
      &lt;td&gt;478&lt;/td&gt;
      &lt;td&gt;508&lt;/td&gt;
      &lt;td&gt;689&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1.06×&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;0.74× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;collection-roundtrip&lt;/td&gt;
      &lt;td&gt;939&lt;/td&gt;
      &lt;td&gt;1,060&lt;/td&gt;
      &lt;td&gt;1,380&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;1.13×&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;0.77× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;model-instantiation&lt;/td&gt;
      &lt;td&gt;0.671&lt;/td&gt;
      &lt;td&gt;2.02&lt;/td&gt;
      &lt;td&gt;12.1&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;3.01×&lt;/strong&gt; 🔴&lt;/td&gt;
      &lt;td&gt;0.17× ✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;model-serialization&lt;/td&gt;
      &lt;td&gt;10.1&lt;/td&gt;
      &lt;td&gt;2.05&lt;/td&gt;
      &lt;td&gt;4.56&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;0.20× 🚀&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;0.45× ✅&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;summary-of-findings&quot;&gt;Summary of Findings&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Near Parity on the Hot Paths:&lt;/strong&gt; For standard reads (get-by-pk), inserts, deletes, and basic limited queries, coodie is operating with a completely negligible overhead compared to writing raw CQL by hand (usually hovering around 5-13% tax). It also outperforms cqlengine across the board on these operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pydantic V2 is a beast:&lt;/strong&gt; We need to remember that Pydantic V2 is basically a blazing-fast Rust engine wearing a Python trench coat. The data validation, object instantiation, and serialization happen at the speed of Rust, keeping the overhead minimal from the start. Just look at the serialization and batch performance multipliers!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The AI kept it lean:&lt;/strong&gt; The code the LLM generated wasn’t building massive ASTs or doing unnecessary query translations. coodie essentially formats a clean dictionary and hands it straight to the underlying Scylla driver to do its native magic. It gets out of the way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lessons Learned (&lt;a href=&quot;https://github.com/fruch/coodie/pull/190&quot;&gt;PR #190&lt;/a&gt;):&lt;/strong&gt; Even with great initial numbers, running the full benchmark suite revealed bottlenecks on things like partial-update and count. We realized we were doing redundant data validation during read operations when fetching data we already knew was valid straight from the database. By bypassing the extra validation pass and loading the raw rows more directly into the Pydantic models (using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model_construct()&lt;/code&gt; for DB data), we can shave off the remaining overhead.&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;So, maybe ORM/ODM are not dead? Yet…&lt;/p&gt;

&lt;p&gt;If the final overhead of using an ODM on hot paths is a measly 5-13%, but in exchange I get full type-safety, declarative schemas, and zero boilerplate, I am taking the ODM every single time.&lt;/p&gt;

&lt;p&gt;It seems my digital sidekick built something that is actually production-ready, and with a little bit of human-driven optimization, it screams.&lt;/p&gt;

&lt;p&gt;You can check out the code, star it, or run your own tests over at &lt;a href=&quot;https://github.com/fruch/coodie&quot;&gt;github.com/fruch/coodie&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;PRs are welcome. יאללה, let’s see how fast we can make it.&lt;/p&gt;

</description>
				<pubDate>Fri, 06 Mar 2026 00:00:00 +0000</pubDate>
				<link>https://fruch.github.io/python/2026/03/06/maybe-orm-odm-not-dead-yet</link>
				<guid isPermaLink="true">https://fruch.github.io/python/2026/03/06/maybe-orm-odm-not-dead-yet</guid>
			</item>
		
			<item>
				<title>Coodie: A 4-year-old idea brought to life by AI (and some coffee)</title>
				<description>
&lt;p&gt;So, let’s rewind a bit. About four years ago, I was looking at &lt;a href=&quot;https://github.com/roman-right/beanie&quot;&gt;Beanie&lt;/a&gt; — this really nifty, Pydantic-based ODM for MongoDB. And as someone who spends an unhealthy amount of time deep in the trenches of ScyllaDB and Cassandra, I had a thought: “Where is &lt;em&gt;my&lt;/em&gt; Beanie? I want a hoodie, but for Cassandra.” And thus, the name was born: &lt;strong&gt;coodie&lt;/strong&gt; = &lt;strong&gt;c&lt;/strong&gt;assandra + beanie (h&lt;strong&gt;oodie&lt;/strong&gt;). Catchy, right?&lt;/p&gt;

&lt;p&gt;Like any respectable developer, I rushed to GitHub, created the repository &lt;a href=&quot;https://github.com/fruch/coodie&quot;&gt;fruch/coodie&lt;/a&gt;, maybe wrote a highly ambitious &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;README.md&lt;/code&gt;, set up a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyproject.toml&lt;/code&gt;, and then… absolutely nothing. Crickets. Life happened. I had CI pipelines to fix, Scylla drivers to maintain, conferences like PyConIL and EuroPython to attend, and live-tweeting to do. coodie just sat there, gathering digital dust, a glorious monument to my good intentions and severe lack of free time.&lt;/p&gt;

&lt;h2 id=&quot;fast-forward-to-today-the-ai-era&quot;&gt;Fast forward to today. The AI era.&lt;/h2&gt;

&lt;p&gt;We are living in a weird timeline where LLMs are everywhere, threatening to take our jobs while simultaneously failing to center a div. People are talking about AI coding assistants non-stop. I myself was quite happy with my usual workflow, but I figured — why not take my 4-year-old fever dream for a walk in the park and feed it to the machine?&lt;/p&gt;

&lt;p&gt;I threw the basic concept at an AI. I gave it some ground rules: it has to use Pydantic v2, it needs to be backed by &lt;a href=&quot;https://github.com/scylladb/python-driver&quot;&gt;scylla-driver&lt;/a&gt;, and it needs to feel as magical as Beanie.&lt;/p&gt;

&lt;p&gt;And holy crap. It actually worked.&lt;/p&gt;

&lt;p&gt;I spent four years procrastinating on this, and a glorified autocomplete bot basically bootstrapped the whole thing while I was sipping my morning coffee. I’m not sure if I should be proud of my newfound status as a “prompt engineer,” or slightly terrified that my open-source street cred is now partially owned by a matrix of weights and biases.&lt;/p&gt;

&lt;h2 id=&quot;the-sweet-setup-we-have-now&quot;&gt;The sweet setup we have now&lt;/h2&gt;

&lt;p&gt;Despite the AI doing the heavy lifting, the architecture actually makes a lot of sense. Here is what coodie brings to the table:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Pydantic v2 all the way&lt;/strong&gt;: Define your documents with full type-checking support.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Declarative schemas&lt;/strong&gt;: You just annotate fields with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PrimaryKey&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClusteringKey&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Indexed&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Counter&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Automatic table management&lt;/strong&gt;: You call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sync_table()&lt;/code&gt; and it creates or evolves the table idempotently. No more writing raw CQL just to add a column.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Sync and Async APIs&lt;/strong&gt;: Because why choose? You can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;coodie.aio&lt;/code&gt; if you are riding the asyncio train, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;coodie.sync&lt;/code&gt; if you want blocking code.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Chainable QuerySets&lt;/strong&gt;: Doing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await Product.find(brand=&quot;Acme&quot;).limit(10).all()&lt;/code&gt; just feels right.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a quick taste of what the AI and I managed to cook up:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;typing&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Annotated&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;uuid&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uuid4&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pydantic&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Field&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;coodie&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init_coodie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PrimaryKey&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Annotated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PrimaryKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;default_factory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uuid4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Settings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;keyspace&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;my_ks&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then querying it is a breeze:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# async
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;products&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;brand&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Acme&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;price&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;The AI works out of the box with almost zero friction. It’s very impressive, and honestly, a bit surreal to see an idea you abandoned years ago suddenly have a passing CI suite, complete with tests and GitHub Actions (which are still very tidy to look at, by the way).&lt;/p&gt;

&lt;p&gt;You can check out the code, star it, or fork it over at &lt;a href=&quot;https://github.com/fruch/coodie&quot;&gt;github.com/fruch/coodie&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;PRs are welcome. Preferably written by humans, but honestly… I guess I can’t really enforce that anymore, can I? יאללה, let’s see how it goes.&lt;/p&gt;

</description>
				<pubDate>Tue, 24 Feb 2026 00:00:00 +0000</pubDate>
				<link>https://fruch.github.io/python/2026/02/24/coodie-ai-pydantic-odm</link>
				<guid isPermaLink="true">https://fruch.github.io/python/2026/02/24/coodie-ai-pydantic-odm</guid>
			</item>
		
			<item>
				<title>Takes from pyconil 2022</title>
				<description>
&lt;h1 id=&quot;takes-from-pyconil-2022&quot;&gt;Takes from pyconil 2022&lt;/h1&gt;

&lt;p&gt;First in person conference I attend since Covid-19, was fun to meet some of the familiar faces
and meet a few new ones.
I’ve tried live tweeting, but seem like I’m not very good at it. (I’m better at hijacking others live tweets)&lt;/p&gt;

&lt;h2 id=&quot;day-1&quot;&gt;Day 1&lt;/h2&gt;

&lt;h3 id=&quot;keynote&quot;&gt;Keynote&lt;/h3&gt;
&lt;p&gt;Keynote speaker couldn’t make it, and was replaced by a panel of the known experts in python
While Sim Zacks asks them popular questions about python&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/alonisser&quot;&gt;@alonisser&lt;/a&gt; and I were a bit surprised, and &lt;a href=&quot;https://twitter.com/alonisser/status/1541672644273180672&quot;&gt;live tweeted&lt;/a&gt; the panel session:&lt;/p&gt;

&lt;h3 id=&quot;hidden-cost-of-your-favorite-function&quot;&gt;&lt;a href=&quot;https://cfp.pycon.org.il/conference2022/talk/NZQNPP/&quot;&gt;Hidden cost of your favorite function&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/mayaGBar&quot;&gt;@mayaGBar&lt;/a&gt; was talking about reason to profile,
and the importance of looking under the hood of the utilities and functions
we use and demonstrated using a profiler comparing different numpy function
to achieve the same goal.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/IsraelFruchter/status/1541687491480244224&quot;&gt;my live tweet&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;hidden-hacks-in-linters-for-better--more-secure-code&quot;&gt;&lt;a href=&quot;https://cfp.pycon.org.il/conference2022/talk/SGNBSX/&quot;&gt;Hidden Hacks in Linters for Better &amp;amp; More Secure Code&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/gemanor&quot;&gt;@gemanor&lt;/a&gt; explained about a use case he and his team need to build lint checkers
for block different personas form doing things that shouldn’t.&lt;/p&gt;

&lt;p&gt;even that he introduce him self as non-pythonista (“alien” in his words), he managed
to showcase a high level python craftsmanship, and a fun talk overall. he’s my MVP 
for this day&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/IsraelFruchter/status/1541696046782365696&quot;&gt;my live tweet&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;what-happens-when-you-import-a-module&quot;&gt;&lt;a href=&quot;https://cfp.pycon.org.il/conference2022/talk/XNGJKS/&quot;&gt;What happens when you import a module?&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/reuvenmlerner&quot;&gt;@reuvenmlerner&lt;/a&gt; with very interesting talk about how exactly the import system works
while showing how to implement some parts of it.&lt;/p&gt;

&lt;p&gt;while drinking the morning coffee, we had a talk with Reuven (me and someone I don’t remember his name..)
about possible use-cases for using importlib.&lt;/p&gt;

&lt;p&gt;one was for decryption of the sourcecode before executing it, to safeguard
the patented algorithms and company secrets.&lt;/p&gt;

&lt;p&gt;and my use case of using it for testing script that were meant to be run as main module.
which is a nice way to avoid using subprocess, so mocks can be used:
https://github.com/scylladb/scylla/pull/10809/files#diff-a9fc368799be893485a61ba81b9b736b2f3f9918a228351e7d6abe7293011584R104&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/IsraelFruchter/status/1541703184636420096&quot;&gt;my live tweet&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;off-road-profiling---when-the-automated-profilers-just-dont-cut-it&quot;&gt;&lt;a href=&quot;https://cfp.pycon.org.il/conference2022/talk/YJGQNC/&quot;&gt;Off road profiling - when the automated profilers just don’t cut it.&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/ShacharSh&quot;&gt;@ShacharSh&lt;/a&gt; goes over how to manually profile some bits of code, and how the
project he built &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;manprof&lt;/code&gt; can help with that.&lt;/p&gt;

&lt;p&gt;that was last talk for the day, and I’ve could really concentrate on tweeting about it,
but it was very nice to see Shachar talk, and improvise punchlines at the right time
like when someone’s phone rang during his talk.&lt;/p&gt;

&lt;p&gt;It was a shame that his package isn’t yet public (said something about legal didn’t yet improve, which always makes me
a bit sad, that those processes are never straight forward)&lt;/p&gt;

&lt;p&gt;הדרן עלך יום ראשון&lt;/p&gt;

&lt;p&gt;let see how it goes tomorrow&lt;/p&gt;

&lt;h2 id=&quot;day-2&quot;&gt;Day 2&lt;/h2&gt;

&lt;h3 id=&quot;keynote-1&quot;&gt;Keynote&lt;/h3&gt;

&lt;p&gt;This day start with me entering to main hall to see Bitya face staring at me
(A former colleague of mine that gave a &lt;a href=&quot;https://cfp.pycon.org.il/conference/talk/SV7XAD/&quot;&gt;lecture&lt;/a&gt; in pyconil few years back)&lt;/p&gt;

&lt;p&gt;Then the [@Yampeleg] started his colorful keynote, show the behind the scenes of competitive machine learning contexts
and how he played with ML tools to “rig” a bit the results.
and moved to more examples of what you can gain with mixing a bit of different models.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/alonisser&quot;&gt;@alonisser&lt;/a&gt; (צייצינו המקצועי) with more details in his &lt;a href=&quot;https://twitter.com/alonisser/status/1542039268939517956&quot;&gt;live tweet&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;BTW [@Yampeleg] is &lt;a href=&quot;https://twitter.com/Yampeleg/status/1542176257739296768&quot;&gt;asking for forgivness&lt;/a&gt; about what he did. as someone that 
doesn’t have keggle account I’m automatically grant him one&lt;/p&gt;

&lt;h3 id=&quot;how-to-lift-your-tech-debt-curse-with-the-magic-of-the-open-close-principle&quot;&gt;&lt;a href=&quot;https://cfp.pycon.org.il/conference2022/talk/HTDW3P/&quot;&gt;How to Lift Your Tech Debt Curse with the Magic of the Open-Close Principle&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/AmramDor&quot;&gt;@AmramDor&lt;/a&gt; talked about tech debt, start with a kind of “spoken word” show telling
the horrors of how a project degrade during its lifecycle.
then he moved to showing a practical code examples of how refactoring can take place
and a few tips and guidelines on do it smoothly.&lt;/p&gt;

&lt;p&gt;One thing I had missing, in real life every thing is a balance between few options, and
each has its pros and cons. talking a bit about the cons of each refactoring
practice was something I would have loved to hear, for example splitting a function into
multiple method in multiple classes and maybe multiple files, 
might hinder readability of the code (just example, with proper names it might do the opposite)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/IsraelFruchter/status/1542057592855433217&quot;&gt;live tweet&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;optimizing-code-performance-for-python-internals&quot;&gt;&lt;a href=&quot;https://cfp.pycon.org.il/conference2022/talk/GRM8TF/&quot;&gt;Optimizing Code Performance for Python Internals&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/YonatanGoldsch2&quot;&gt;@YonatanGoldsch2&lt;/a&gt; started yet another talk about what seems to be profiling (which that was more than handful of those)
but then supersized me with a deeper talk that shad light into the inner working
of dicts, that I wasn’t aware of and for sure would make me think next time I’m deleting
attributes from objects.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/IsraelFruchter/status/1542063956306665473&quot;&gt;live tweet&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;json---the-fine-print&quot;&gt;&lt;a href=&quot;https://cfp.pycon.org.il/conference2022/talk/YYXQFL/&quot;&gt;JSON - The Fine Print&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/tebeka&quot;&gt;@tebeka&lt;/a&gt; talks are always a pleasure to attend, and this one was interesting to
see how much can we learn about something as commonly used as json.&lt;/p&gt;

&lt;p&gt;in the end I didn’t learn anything surprisingly new, but Miki exampled a few of the 
things people should remember when reading/parsing json, for example handling datatime
of bytes.&lt;/p&gt;

&lt;p&gt;BTW I know that the json parser have advanced features, like hooks Miki showed. 
but I never ever used them, I probably should start.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/IsraelFruchter/status/1542101199553544192&quot;&gt;live tweet&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;overcoming-concurrency-issues-in-web-applications&quot;&gt;&lt;a href=&quot;https://cfp.pycon.org.il/conference2022/talk/EKQMGL/&quot;&gt;Overcoming Concurrency Issues in Web Applications&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/be_haki&quot;&gt;@be_haki&lt;/a&gt; gave a great and funny talk, on a subject very dear to my heart, since I was facing almost the exact same 
things a few years back. (and I’m work for &lt;a href=&quot;https://twitter.com/scylladb&quot;&gt;@scylladb&lt;/a&gt; a DB company for the last 3 years)&lt;/p&gt;

&lt;p&gt;unfortunately for me, we weren’t using SQL DB, but couchbase and mongodb and almost 
none of the suggested solutions fit those DBs, since they by design don’t give similar
guarantees or functions.&lt;/p&gt;

&lt;p&gt;After the talk when I talked with Haki, he was surprised how many people attend (also said that in the beginning of the talk)
I wasn’t surprised, this topic is sound so trivial (once explained) but it so many times forgotten or overlooked
and solutions to some of those type of problems are not easy to implement on different types of DBs,
you need a higher the usual understanding of the specific DB you are working with.&lt;/p&gt;

&lt;p&gt;(I think I should take this one to our experts to see their suggestions)&lt;/p&gt;

&lt;p&gt;I was so enjoying the talk, I’ve forgotten about tweeting, Alon is better tweeter (and he should get a raise for that)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/alonisser/status/1542110086482563073&quot;&gt;alon’s live tweet&lt;/a&gt;&lt;/p&gt;

</description>
				<pubDate>Tue, 28 Jun 2022 19:52:00 +0000</pubDate>
				<link>https://fruch.github.io/2022/06/28/pyconil-2022</link>
				<guid isPermaLink="true">https://fruch.github.io/2022/06/28/pyconil-2022</guid>
			</item>
		
			<item>
				<title>Taking Github Actions for a walk in the park</title>
				<description>
&lt;h1 id=&quot;taking-github-actions-for-a-walk-in-the-park&quot;&gt;Taking Github Actions for a walk in the park&lt;/h1&gt;

&lt;h2 id=&quot;travis-started-to-scare-me-a-bit&quot;&gt;Travis started to scare me a bit&lt;/h2&gt;

&lt;p&gt;People were talking about github actions for a while now, lot of hype around it.
I myself was quite happy with the things I’ve managed to get done with &lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But then came in this announcement from travis: &lt;a href=&quot;https://blog.travis-ci.com/2020-11-02-travis-ci-new-billing&quot;&gt;“The new pricing model for travis-ci.com”&lt;/a&gt;.
I was reading via lot of the backlash in tweeter about it, and after carefully reading the announcement itself, I was starting to think that the work I did for &lt;a href=&quot;https://github.com/scylladb/python-driver&quot;&gt;scylla-driver&lt;/a&gt; was counting on &lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis&lt;/a&gt; too much.&lt;/p&gt;

&lt;p&gt;Recently I’ve start seeing long queues for job triggers in travis, and I was starting to have second thoughts about picking travis. (not so long ago, less than a year ago)&lt;/p&gt;

&lt;h2 id=&quot;the-sweet-setup-i-had-in-travis&quot;&gt;The sweet setup I had in Travis&lt;/h2&gt;

&lt;p&gt;As a recap for &lt;a href=&quot;https://github.com/scylladb/python-driver&quot;&gt;scylla-driver&lt;/a&gt;, since it’s a c based package, heavily using &lt;a href=&quot;https://cython.org/&quot;&gt;cython&lt;/a&gt;.
We are building python wheels for windows, mac, linux, ranging from python2.7 to python3.9, and pypy. (also using the &lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis&lt;/a&gt; experimental aarch64 and ppc64le support)&lt;/p&gt;

&lt;p&gt;For building the wheels we are using &lt;a href=&quot;https://github.com/joerick/cibuildwheel&quot;&gt;cibuildwheel&lt;/a&gt;, which is a nifty tool that magically keep all know how, on how building wheels correctly on multiple platforms.
In linux, it’s using the official docker images provided by the [Python Packaging Authority
] for manylinux2014.
And on windows and mac equivalents with the correct set to needed tool to get you wheel happily containing all the need dynamic libraries it depended on&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/joerick/cibuildwheel&quot;&gt;cibuildwheel&lt;/a&gt; also comes with readily available examples for all the major CI system out there&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://travis-ci.org/github/scylladb/python-driver/builds/709882917&quot;&gt;&lt;img src=&quot;https://fruch.github.io/assets/img/python-driver-release.png&quot; width=&quot;100%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/joerick/cibuildwheel&quot;&gt;cibuildwheel&lt;/a&gt; is also helping you in running unittest ontop of each built wheel (since in my case the setup is a bit complex, getting it installed and compile across the board was hard, we we’re skipping some unittest on some platforms)&lt;/p&gt;

&lt;p&gt;Travis was also running our integration test suite, and running it on our PRs, and automatically uploading all the wheels and source distribution to Pypi.&lt;/p&gt;

&lt;p&gt;I was working on this setup for long week, with a tight deadline for it to be ready for &lt;a href=&quot;https://ep2020.europython.eu/&quot;&gt;europython2020&lt;/a&gt;, thanks to &lt;a href=&quot;https://twitter.com/ultrabug&quot;&gt;@ultrabug&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;github-actions&quot;&gt;Github actions&lt;/h2&gt;

&lt;p&gt;For a while I was a bit unsure if it would be a match to what I had in travis. But one day our own Jenkins server was down for maintenance, and a big portion of my day was clear case of that.&lt;/p&gt;

&lt;p&gt;I’ve started with copy-pasting &lt;a href=&quot;https://github.com/joerick/cibuildwheel&quot;&gt;cibuildwheel&lt;/a&gt; github actions &lt;a href=&quot;https://cibuildwheel.readthedocs.io/en/stable/setup/#github-actions&quot;&gt;example&lt;/a&gt;, and worked my way from there.&lt;/p&gt;

&lt;p&gt;When I’ve started adding all the different unittest and platforms, I was struggling a bit with how the matrix is working, and how conditional steps works.&lt;/p&gt;

&lt;p&gt;It ended up something like this, almost identical to what I had in travis:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build and upload to PyPi&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pull_request&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;build_wheels&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Build wheels $ ($)&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;contains(github.event.pull_request.labels.*.name, &apos;test-build&apos;) || github.event_name == &apos;push&apos; &amp;amp;&amp;amp; endsWith(github.event.ref, &apos;scylla&apos;)&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;fail-fast&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;matrix&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-18.04&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;x86_64&lt;/span&gt;

          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-18.04&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;i686&lt;/span&gt;

          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ubuntu-18.04&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PyPy&lt;/span&gt;

          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;windows-latest&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;win32&lt;/span&gt;

          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;windows-latest&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;win64&lt;/span&gt;

          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;windows-latest&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PyPy&lt;/span&gt;

          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;macos-latest&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;all&lt;/span&gt;

          &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;macos-latest&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PyPy&lt;/span&gt;

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

&lt;p&gt;We had a nice twist that we didn’t have before, but now we can control from github PR which part of my pipeline would run using label, since github actions is so tightly integrated you can lookup almost anything related to the PR.&lt;/p&gt;

&lt;h2 id=&quot;github-actions---ui&quot;&gt;Github Actions - UI&lt;/h2&gt;

&lt;p&gt;This is how the final thing looks like:
&lt;a href=&quot;https://github.com/scylladb/python-driver/actions/runs/446668339&quot;&gt;&lt;img src=&quot;https://fruch.github.io/assets/img/github_actions.png&quot; width=&quot;100%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;logging is a bit weird to watch while it’s running, but after the fact the log are very tidy to look at&lt;/p&gt;

&lt;h2 id=&quot;late-surprise---cross-compile-using-qemu&quot;&gt;Late surprise - cross compile using qemu&lt;/h2&gt;

&lt;p&gt;With almost perfect timing I’ve run into this
https://github.com/joerick/cibuildwheel/pull/482
by &lt;a href=&quot;https://github.com/asfaltboy&quot;&gt;Pavel Savchenko&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was trying all kind of things to get aarch64 support, but this PR figure it out quite nicely, with one magic step:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Set up QEMU&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;qemu&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;docker/setup-qemu-action@v1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;platforms&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For reference the full &lt;a href=&quot;https://github.com/scylladb/python-driver/actions/runs/446668338/workflow&quot;&gt;workflow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can have docker using qemu to run docker instances based on different cpu architecture, it’s horribly slow but it’s working.&lt;/p&gt;

&lt;p&gt;And nice side effect I’ve learned how to run it locally, so I can debug those things. Something I haven’t figured when running with Travis, apparently travis was using the same trick on their experimental support for those architectures.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Github actions works out of the box, with almost zero fraction, almost anything I could think about I’ve found a readily available step I can pickup, very impressing.&lt;/p&gt;

&lt;p&gt;One thing I haven’t yet tried out, is using self hosted runner, hopefully I won’t need it.
Cause who want to babysit anther server on his own, or worse, a bunch of them.&lt;/p&gt;

</description>
				<pubDate>Tue, 29 Dec 2020 00:00:00 +0000</pubDate>
				<link>https://fruch.github.io/2020/12/29/github-actions</link>
				<guid isPermaLink="true">https://fruch.github.io/2020/12/29/github-actions</guid>
			</item>
		
			<item>
				<title>How much fun was EuroPython 2020</title>
				<description>
&lt;h1 id=&quot;how-much-fun-was-europython-2020&quot;&gt;How much fun was EuroPython 2020&lt;/h1&gt;

&lt;h2 id=&quot;pyconil-got-canceled&quot;&gt;&lt;a href=&quot;https://pycon.org.il/2020/&quot;&gt;#pyconil&lt;/a&gt; got canceled&lt;/h2&gt;

&lt;p&gt;This year I’ve finally got enough courage and will, and I had 2 submissions for &lt;a href=&quot;https://pycon.org.il/2020/&quot;&gt;#pyconil&lt;/a&gt;.
COVID-19 had other plans, and &lt;a href=&quot;https://pycon.org.il/2020/&quot;&gt;#pyconil&lt;/a&gt; was canceled&lt;/p&gt;

&lt;p&gt;I’ve told &lt;a href=&quot;https://twitter.com/ultrabug&quot;&gt;@ultrabug&lt;/a&gt; about this (Numberly CTO, Alexys Jacob), after a few weeks he surprised me with telling me he’s gonna present &lt;a href=&quot;(https://github.com/scylladb/python-driver)&quot;&gt;scylla-driver&lt;/a&gt; in europython2020, the shard-aware driver we were working on in the last 6 months.&lt;/p&gt;

&lt;p&gt;At the time it wasn’t yet ready nor publish.
(Also found out that Numberly were sponsoring europython for years now)
Took me a few seconds to figure that he just set me deadline without my consent…&lt;/p&gt;

&lt;p&gt;Fast-forwarding a bit, and &lt;a href=&quot;(https://github.com/scylladb/python-driver)&quot;&gt;scylla-driver&lt;/a&gt; initial release came out: 
https://pypi.org/project/scylla-driver/3.21.0/&lt;/p&gt;

&lt;p&gt;And my tickets for europython2020 were booked…&lt;/p&gt;

&lt;h2 id=&quot;discord-is-fun&quot;&gt;Discord is fun&lt;/h2&gt;

&lt;p&gt;Few days before the date, I’ve got an email with instruction to connect to the discord of europython2020, since it’s my first COVID-19 online conference, I’ve registered and login straight away.&lt;/p&gt;

&lt;p&gt;It was really nice to be start to start talking with people and meet them a few days before&lt;/p&gt;

&lt;p&gt;Each track got its own chat room, backed with zoom webinar and online youtube stream
each talk got its own chat room, so people can promote their and answer question before and after the talks.
Sponsors had rooms too, and all the sprints had rooms (we’ll get to that later on)&lt;/p&gt;

&lt;p&gt;Talk about timing, day before europython2020, this press release came out
https://www.scylladb.com/press-release/discord-chooses-scylla-core-storage-layer/&lt;/p&gt;

&lt;h2 id=&quot;talks--day-1&quot;&gt;Talks — Day 1&lt;/h2&gt;

&lt;p&gt;The opening keynote was cancelled cause of technical difficulties, that lost touch with whom was supposed to talk. (it rescheduled to next day)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://github.com/eliasmistler&quot;&gt;Elias Mistler&lt;/a&gt; was talking about &lt;a href=&quot;https://ep2020.europython.eu/talks/83SnxW9-how-to-write-multi-paradigm-code/&quot;&gt;“How to write multi-paradigm code”&lt;/a&gt; show casing and coding live a sudoku solver, with functional and object originated approaches, and how to mix them both.
The code is available as &lt;a href=&quot;https://github.com/eliasmistler/europython2020-multi-paradigm-sudoku&quot;&gt;notebook&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/boyan-miletic/&quot;&gt;Bojan Miletic&lt;/a&gt; was talking about &lt;a href=&quot;https://ep2020.europython.eu/talks/5e5RyUN-django-testing-on-steroird-pytest-hypothesis/&quot;&gt;“Django Testing on Steroid: pytest + Hypothesis”&lt;/a&gt; — shows the basic usage of hypothesis, I’m hear about hypothesis all over the place, maybe it will bring me one step close to use is in one of my projects&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://twitter.com/MartinChristen&quot;&gt;Martin Christen&lt;/a&gt; gave a very cool demo of &lt;a href=&quot;https://ep2020.europython.eu/talks/3TkNjfe-pyrt-computer-graphics-in-jupyter-notebooks-for-fun-and-teaching/&quot;&gt;“pyRT - Computer Graphics in Jupyter Notebooks for Fun and Teaching”&lt;/a&gt; - I love Jupyter notebook visual trick, and I love 3d. So this one I enjoyed a lot, Martin was quite a performer and funny. I strongly recommend trying out the &lt;a href=&quot;https://github.com/martinchristen/EuroPython2020&quot;&gt;demo&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://twitter.com/gjbernat&quot;&gt;Bernat Gabor&lt;/a&gt; gave an excellent talk
&lt;a href=&quot;https://ep2020.europython.eu/talks/D2SG8Vb-lessons-from-the-trenches-rewriting-and-re-releasing-virtualenv/&quot;&gt;“Lessons from the Trenches: rewriting and re-releasing virtualenv”&lt;/a&gt;
about a big refactoring virtualenv had, packaging is a subject close to my heart. This is an excellent lesson on how to approach major refactor and a reminder that it would always take more time than you’ll estimate it.
I must say that this change, from a POV of a heavy user of virtualenv, wasn’t even noticed.
When he was demoing a few things I’ve realized that I’ve seen it in logs, but didn’t know the big story happing behind the scenes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;In the next one, &lt;a href=&quot;https://twitter.com/pdgjones&quot;&gt;Philip Jones&lt;/a&gt; was building a ASGI server from scratch, show the details of the ASGI protocol — &lt;a href=&quot;https://ep2020.europython.eu/talks/4g2en8S-an-asgi-server-from-scratch/&quot;&gt;“An ASGI Server from scratch”&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://ep2020.europython.eu/talks/a-deep-dive-and-comparison-of-python-drivers-for-cassandra-and-scylla/&quot;&gt;“A deep dive and comparison of Python drivers for Cassandra and Scylla”&lt;/a&gt; — &lt;a href=&quot;https://twitter.com/ultrabug&quot;&gt;Alexys&lt;/a&gt; great slides (which I had a peek at few days before)with lot of emojis, going down to the details of how cassandra/scylla hash ring works, and how scylla shard share nothing architecture is use by the &lt;a href=&quot;(https://github.com/scylladb/python-driver)&quot;&gt;scylla-driver&lt;/a&gt; fork we work on for the last few months.
And he finished with data from Numberly production before/after moving to shard aware client, 2x-2.5x speed up in response time
I was live tweeting the whole thing into our company slack…&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ep2020.europython.eu/talks/5PDef3W-elegant-exception-handling/&quot;&gt;“Elegant Exception Handling”&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ep2020.europython.eu/talks/CeKGczx-best-practices-for-production-ready-docker-packaging/&quot;&gt;“Best practices for production-ready Docker packaging”&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ep2020.europython.eu/talks/4yCL9yy-pluggable-architecture/&quot;&gt;“Pluggable Architecture”&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ep2020.europython.eu/talks/6Le7GKY-writing-zenlike-python/&quot;&gt;“Writing Zenlike Python”&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;social--the-missing-e-in-my-whisky&quot;&gt;Social — the missing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e&lt;/code&gt; in my whisky&lt;/h2&gt;

&lt;p&gt;During the whole day I was playing cat and mouse with people, trying to bring them into the open track, to have a face to face meeting,
only later after all the sessions end, some people came in, most of them were the part of the organizing team. Every one where show their beer or whisky that they were drinking. &lt;a href=&quot;https://github.com/kgaughan&quot;&gt;Keith Gaughan&lt;/a&gt; was laughing at the ice in my whisky, and also thought me a real whisky is spelled with whiskey with an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e&lt;/code&gt; in it.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/malemburg&quot;&gt;Marc-Andre Lemburg&lt;/a&gt; was talking about the challenges they have as organizers, one thing led to anther, and I ask how can I help. He said they need a hand with handling the tweeter account, and that he’ll hook me tomorrow with whom handle it.&lt;/p&gt;

&lt;p&gt;After a few more rounds of whisky, I call it a day.&lt;/p&gt;

&lt;h2 id=&quot;talks--day-2&quot;&gt;Talks — Day 2&lt;/h2&gt;

&lt;p&gt;TODO:&lt;/p&gt;

&lt;h2 id=&quot;sprints&quot;&gt;Sprints&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;packaging -&lt;/li&gt;
  &lt;li&gt;hypothesis -&lt;/li&gt;
  &lt;li&gt;terminusdb-client -&lt;/li&gt;
&lt;/ul&gt;

</description>
				<pubDate>Wed, 29 Jul 2020 00:00:00 +0000</pubDate>
				<link>https://fruch.github.io/2020/07/29/europython-2020</link>
				<guid isPermaLink="true">https://fruch.github.io/2020/07/29/europython-2020</guid>
			</item>
		
			<item>
				<title>Introducing pytest-elk-reporter</title>
				<description>
&lt;h1 id=&quot;pytest-elk-reporter&quot;&gt;pytest-elk-reporter&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;tl;td&lt;/strong&gt;: https://github.com/fruch/pytest-elk-reporter&lt;/p&gt;

&lt;h2 id=&quot;history&quot;&gt;History&lt;/h2&gt;
&lt;p&gt;Few years back I’ve wrote a post about how I’ve connected python based test to ELK setup - &lt;a href=&quot;http://fruch.github.io/blog/2014/10/30/ELK-is-fun&quot;&gt;“ELK is fun”&lt;/a&gt;, it was using an xunit xml, parsing it and sending it via Logstash.&lt;/p&gt;

&lt;p&gt;Over time I’ve learn a lot about ElasticSearch and it’s friend Kibana, using them as a tool to handle logs. and also as a backend for a search component on my previous job.&lt;/p&gt;

&lt;p&gt;So now I know logstash isn’t needed for reporting test result, posting straight into elasticsearch is easier and gives you better control, ES is doing anything “automagiclly” anyhow nowadays.&lt;/p&gt;

&lt;h2 id=&quot;what-can-it-do-&quot;&gt;What can it do ?&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;collect&lt;/strong&gt; as much information as you can about one test results and running environment and send it to elasticsearch.
    &lt;ul&gt;
      &lt;li&gt;data like git commit/sha from current directory&lt;/li&gt;
      &lt;li&gt;jenkins environment variables, like job id and username triggered the job.&lt;/li&gt;
      &lt;li&gt;cool tracebacks which pytest excels at.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;extend&lt;/strong&gt; - let user configure (like target address and credentials) it from code, and add data of their own to each session or test.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;tricks-ive-picked-on-the-way&quot;&gt;Tricks I’ve picked on the way&lt;/h2&gt;

&lt;p&gt;Every time I start a new package, I learn a few new things, here’s a few I’m happy about this time:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Created the package with &lt;a href=&quot;https://github.com/pytest-dev/cookiecutter-pytest-plugin&quot;&gt;cookiecutter-pytest-plugin&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;I’m using &lt;a href=&quot;https://pre-commit.com&quot;&gt;pre-commit&lt;/a&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;a href=&quot;https://github.com/python/black&quot;&gt;black&lt;/a&gt; - instead of the old friend &lt;a href=&quot;https://github.com/hhatto/autopep8&quot;&gt;autopep8&lt;/a&gt;.&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;&lt;a href=&quot;https://www.pylint.org/&quot;&gt;pylint&lt;/a&gt; in both python27 and python36 to keep the code clean of silly mistakes.&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://travis-ci.org/fruch/pytest-elk-reporter&quot;&gt;Travis&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;build and test with Tox on all possible python versions.&lt;/p&gt;

    &lt;p&gt;also uploading wheels to pypi based on tags.&lt;/p&gt;

    &lt;p&gt;thanks to &lt;a href=&quot;https://github.com/pypa/setuptools_scm&quot;&gt;setuptools_scm&lt;/a&gt; version no need to edit files for setting version number.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://ci.appveyor.com/project/fruch/pytest-elk-reporter&quot;&gt;Appveyor&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;I also cover windows own little issue (non found so far).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://codecov.io/gh/fruch/pytest-elk-reporter/commits&quot;&gt;Codecov&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;really like that it can collect from multiple run, for example both linux and windows tests run, which helps to show the total coverage.&lt;/p&gt;

    &lt;p&gt;got me to 93% line coverage (and going down as I add more code).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;the-bad-stuff---aka-things-i-need-to-improve&quot;&gt;The bad stuff - a.k.a things I need to improve&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt; - I’ve mostly wrote test, zero docs.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Name&lt;/strong&gt; - it’s a bit boring, and might conflict with other plugins.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Kibana Dashboards examples&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;I should really include some sample kibana dashboard to show the strength of it, it’s own test data is a bit boring.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;auto generating and upload of docs&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;I’ve tried using Travis Deploy to github Pages, didn’t exactly nailed, or got it working as I expect, maybe I should try &lt;a href=&quot;https://readthedocs.org/&quot;&gt;readthedocs&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;pytest-xdist&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;I still need to test it with xdist, it’s going to make thing a more tricker, as usual.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-you-should-next&quot;&gt;What you should next&lt;/h2&gt;

&lt;p&gt;Go grab &lt;a href=&quot;https://github.com/fruch/pytest-elk-reporter&quot;&gt;it&lt;/a&gt;, git it a star, fork it.&lt;/p&gt;

&lt;p&gt;I’m waiting for your PRs, and your stories on how it’s help you tame a whole bunch of tests.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;    &lt;span class=&quot;c&quot;&gt;# forgot to show how to install :\&lt;/span&gt;
    pip &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;pytest-elk-reporter&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
</description>
				<pubDate>Mon, 24 Jun 2019 00:00:00 +0000</pubDate>
				<link>https://fruch.github.io/2019/06/24/pytest-elk-reporter</link>
				<guid isPermaLink="true">https://fruch.github.io/2019/06/24/pytest-elk-reporter</guid>
			</item>
		
			<item>
				<title>KISS - Keep it shorter short</title>
				<description>
&lt;p&gt;Today on work on a python related mailing list someone sent this snippet of code he didn’t wrote.
and that was causing some of the server he worte/manged some troubles.&lt;/p&gt;

&lt;p&gt;Here’s the code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;deploy_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;full_path_to_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_to_file&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_to_file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;print_error_exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot; wrong input for deploy_file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;post_status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;full_path_to_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;rb&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Deploying...:  %s&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;file_content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;post_status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post_status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post_status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;201&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post_status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;202&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Success:  %s&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;uploaded&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file_to_upload&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;print_error_exit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Deployment to %s failed. status_code = %s, returned_text = %s&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post_status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post_status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;print_error_exit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Posting with url %s failed. status: %s&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post_status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;First thought I hade was, the one wrote it is must be coming from C (or maybe Java), so let go over what’s wrong here.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Input validation&lt;/p&gt;

    &lt;p&gt;I don’t know what’s print_error_exit() is doing exactly, let’s assume it’s raising expection (hopefully it’s not calling os.exit())  &lt;br /&gt;
 So assertion with the proper text would be alsmot identical.&lt;/p&gt;

    &lt;p&gt;Checking both for None, and for empty string is futile, just assert, like this:&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;        &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_to_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;parameter can&apos;t be empty&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;parameter can&apos;t be empty&quot;&lt;/span&gt;
    &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Using requests to stream file&lt;/p&gt;

    &lt;p&gt;Requests is cool, alsmot the defacto standard when HTTP client is need in python.
 it has very good documention, clearly someone didn’t read it.&lt;a href=&quot;http://docs.python-requests.org/en/master/user/advanced/#streaming-uploads&quot;&gt;streaming uploads&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Multiple error paths&lt;/p&gt;

    &lt;p&gt;Lot of different error handling code, one for checking the http statuses and one for catching expections.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;my-version&quot;&gt;My version&lt;/h1&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;deploy_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;full_path_to_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_to_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;parameter can&apos;t be empty&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;parameter can&apos;t be empty&quot;&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;full_path_to_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;rb&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Deploying...:  %s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

                &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

                &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_code&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;201&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;202&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Success:  %s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;uploaded&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file_to_upload&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;deploy_file faild&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# so we&apos;ll have a nice print in the log
&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# casue I don&apos;t know what print_error_exit() does, we&apos;ll call it.
&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# even that I would prefer to just raise the expection up, i.e. &quot;raise ex&quot;
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;print_error_exit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Deployment to %s failed. status_code = %s, returned_text = %s&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; 
                &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;full_path_in_server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_code&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
				<pubDate>Fri, 08 Jul 2016 00:00:00 +0000</pubDate>
				<link>https://fruch.github.io/2016/07/08/kiss-keep-it-shorter-short</link>
				<guid isPermaLink="true">https://fruch.github.io/2016/07/08/kiss-keep-it-shorter-short</guid>
			</item>
		
			<item>
				<title>Taming the logging formatter</title>
				<description>
&lt;p&gt;We love logging, and we use it all around our code. (it’s the standard/built-in/batteries included)&lt;/p&gt;

&lt;p&gt;We have those hugh json objects flying around, we want to log them.&lt;/p&gt;

&lt;p&gt;pprint.pformat comes handy for those cases:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pprint&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;my_large_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my large inforamtion&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dicts, dicts, dicts,&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;??&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;***&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
                  &lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my large inforamtion&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;how we love big dicts ?&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;??&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;***&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
                  &lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my large inforamtion&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;how we love big dicts ? don&apos;t we ?,&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;???&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;***&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Mary &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; had &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; a &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; little &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; lamb&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pprint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pformat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;my_large_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pprint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pformat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;my_large_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;but when used with complex formatter the output goes like that:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;^14/11/06 00:58:39 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:74 &amp;gt; Mary
 had
 a
 little
 lamb
^14/11/06 00:58:39 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:75 &amp;gt; [{&apos;data&apos;: &apos;my large inforamtion&apos;,
  &apos;data1&apos;: &apos;dicts, dicts, dicts,&apos;,
  &apos;data3&apos;: {&apos;a&apos;: &apos;??&apos;, &apos;b&apos;: 2, &apos;c&apos;: 3, &apos;d&apos;: &apos;***&apos;}},
 {&apos;data&apos;: &apos;my large inforamtion&apos;,
  &apos;data1&apos;: &apos;how we love big dicts ?&apos;,
  &apos;data3&apos;: {&apos;a&apos;: &apos;??&apos;, &apos;b&apos;: 2, &apos;c&apos;: 3, &apos;d&apos;: &apos;***&apos;}},
 {&apos;data&apos;: &apos;my large inforamtion&apos;,
  &apos;data1&apos;: &quot;how we love big dicts ? don&apos;t we ?,&quot;,
  &apos;data3&apos;: {&apos;a&apos;: &apos;???&apos;, &apos;b&apos;: 2, &apos;c&apos;: 3, &apos;d&apos;: &apos;***&apos;}}]
^14/11/06 00:58:39 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:76 &amp;gt; [{&apos;data&apos;: &apos;my large inforamtion&apos;,
  &apos;data1&apos;: &apos;dicts, dicts, dicts,&apos;,
  &apos;data3&apos;: {&apos;a&apos;: &apos;??&apos;, &apos;b&apos;: 2, &apos;c&apos;: 3, &apos;d&apos;: &apos;***&apos;}},
 {&apos;data&apos;: &apos;my large inforamtion&apos;,
  &apos;data1&apos;: &apos;how we love big dicts ?&apos;,
  &apos;data3&apos;: {&apos;a&apos;: &apos;??&apos;, &apos;b&apos;: 2, &apos;c&apos;: 3, &apos;d&apos;: &apos;***&apos;}},
 {&apos;data&apos;: &apos;my large inforamtion&apos;,
  &apos;data1&apos;: &quot;how we love big dicts ? don&apos;t we ?,&quot;,
  &apos;data3&apos;: {&apos;a&apos;: &apos;???&apos;, &apos;b&apos;: 2, &apos;c&apos;: 3, &apos;d&apos;: &apos;***&apos;}}]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Kinda, not really helpful:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;em&gt;confusing&lt;/em&gt; - and you loose track of where this print came from really fast (keep in mind I’m talking about humongous json object)&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;filtering&lt;/em&gt; is (almost) impossible (yeah, not without some extra regex kung-fu)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Skimmed through the logging documentations, google it a bit think someone already solved those things
and I could copy paste, came out empty handed.&lt;/p&gt;

&lt;p&gt;So here how it can be fixed:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;logging&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MultiLineFormatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Formatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
        split the message into different line and prepend it with the formatting
        :param record:
        :return: the formatted string
        &quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usesTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asctime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;formatTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datefmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__dict__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;message&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_fmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exc_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# Cache the traceback text to avoid converting it multiple times
&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# (it&apos;s constant anyway)
&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exc_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exc_text&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;formatException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exc_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exc_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exc_text&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;UnicodeError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;# Sometimes filenames have non-ASCII chars, which can lead
&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;# to errors when s is Unicode and record.exc_text is str
&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;# See issue 8924.
&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;# We also use replace for when there are multiple
&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;# encodings, e.g. UTF-8 for the filesystem and latin-1
&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;# for a script. See issue 13232.
&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exc_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getfilesystemencoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
                                               &lt;span class=&quot;s&quot;&gt;&apos;replace&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# and two examples how to configure the root logger to use it
&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;logging&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;logging.config&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basicConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;configure_with_api&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;handler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StreamHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;formatter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MultilineFormatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;^%(asctime)s !%(levelname)s &amp;lt;t:%(threadName)s T:%(name)s M:%(filename)s F:%(funcName)s L:%(lineno)d &amp;gt; %(message)s&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                  &lt;span class=&quot;n&quot;&gt;datefmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;%y/%m/%d %H:%M:%S&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;formatter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;formatter&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;configure_with_dictConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dictConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;version&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;disable_existing_loggers&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;formatters&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;multiline&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&apos;()&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MultilineFormatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&apos;format&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;^%(asctime)s !%(levelname)s &amp;lt;t:%(threadName)s T:%(name)s M:%(filename)s F:%(funcName)s L:%(lineno)d &amp;gt; %(message)s&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&apos;datefmt&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;%y/%m/%d %H:%M:%S&apos;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;handlers&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;console&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&apos;class&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;logging.StreamHandler&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&apos;formatter&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;multiline&apos;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&apos;loggers&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&apos;handlers&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;console&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&apos;propagate&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&apos;level&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;INFO&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and now our output is much much clearer:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:74 &amp;gt; Mary
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:74 &amp;gt;  had
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:74 &amp;gt;  a
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:74 &amp;gt;  little
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:74 &amp;gt;  lamb
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:75 &amp;gt; [{&apos;data&apos;: &apos;my large inforamtion&apos;,
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:75 &amp;gt;   &apos;data1&apos;: &apos;dicts, dicts, dicts,&apos;,
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:75 &amp;gt;   &apos;data3&apos;: {&apos;a&apos;: &apos;??&apos;, &apos;b&apos;: 2, &apos;c&apos;: 3, &apos;d&apos;: &apos;***&apos;}},
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:75 &amp;gt;  {&apos;data&apos;: &apos;my large inforamtion&apos;,
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:75 &amp;gt;   &apos;data1&apos;: &apos;how we love big dicts ?&apos;,
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:75 &amp;gt;   &apos;data3&apos;: {&apos;a&apos;: &apos;??&apos;, &apos;b&apos;: 2, &apos;c&apos;: 3, &apos;d&apos;: &apos;***&apos;}},
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:75 &amp;gt;  {&apos;data&apos;: &apos;my large inforamtion&apos;,
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:75 &amp;gt;   &apos;data1&apos;: &quot;how we love big dicts ? don&apos;t we ?,&quot;,
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:75 &amp;gt;   &apos;data3&apos;: {&apos;a&apos;: &apos;???&apos;, &apos;b&apos;: 2, &apos;c&apos;: 3, &apos;d&apos;: &apos;***&apos;}}]
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:76 &amp;gt; [{&apos;data&apos;: &apos;my large inforamtion&apos;,
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:76 &amp;gt;   &apos;data1&apos;: &apos;dicts, dicts, dicts,&apos;,
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:76 &amp;gt;   &apos;data3&apos;: {&apos;a&apos;: &apos;??&apos;, &apos;b&apos;: 2, &apos;c&apos;: 3, &apos;d&apos;: &apos;***&apos;}},
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:76 &amp;gt;  {&apos;data&apos;: &apos;my large inforamtion&apos;,
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:76 &amp;gt;   &apos;data1&apos;: &apos;how we love big dicts ?&apos;,
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:76 &amp;gt;   &apos;data3&apos;: {&apos;a&apos;: &apos;??&apos;, &apos;b&apos;: 2, &apos;c&apos;: 3, &apos;d&apos;: &apos;***&apos;}},
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:76 &amp;gt;  {&apos;data&apos;: &apos;my large inforamtion&apos;,
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:76 &amp;gt;   &apos;data1&apos;: &quot;how we love big dicts ? don&apos;t we ?,&quot;,
^14/11/06 00:54:51 !ERROR &amp;lt;t:MainThread T:root M:log.py F:&amp;lt;module&amp;gt; L:76 &amp;gt;   &apos;data3&apos;: {&apos;a&apos;: &apos;???&apos;, &apos;b&apos;: 2, &apos;c&apos;: 3, &apos;d&apos;: &apos;***&apos;}}]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer: use with caution, written past midnight :)&lt;/strong&gt;&lt;/p&gt;
</description>
				<pubDate>Thu, 06 Nov 2014 00:00:00 +0000</pubDate>
				<link>https://fruch.github.io/2014/11/06/taming-the-logging-formatter</link>
				<guid isPermaLink="true">https://fruch.github.io/2014/11/06/taming-the-logging-formatter</guid>
			</item>
		
			<item>
				<title>ELK is fun</title>
				<description>
&lt;p&gt;As I do a lot of testing and CI in my day job, I took ELK for a test drive.
(ELK stands for &lt;a href=&quot;http://www.elasticsearch.org/overview/elasticsearch/&quot;&gt;ElasticSearch&lt;/a&gt;, &lt;a href=&quot;http://www.elasticsearch.org/overview/logstash/&quot;&gt;LogStash&lt;/a&gt; and &lt;a href=&quot;http://www.elasticsearch.org/overview/kibana/&quot;&gt;Kibana&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I’ve played around with Logstash before, but it’s first time i’m trying Kibana.&lt;/p&gt;

&lt;p&gt;I’ve look for a quick way to setup it, and there where gazillion hits in &lt;a href=&quot;https://registry.hub.docker.com/search?&amp;amp;q=elk&quot;&gt;Docker Hub&lt;/a&gt;
(I’ve forgot which one I’ve actually installed :))
&lt;em&gt;EDIT:&lt;/em&gt; it was cyberabis/docker-elkauto.&lt;/p&gt;

&lt;p&gt;That went quick quickly, with a small change that I’ve used port 81&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://fruch.github.io/assets/img/ELK.jpg&quot;&gt;&lt;img src=&quot;https://fruch.github.io/assets/img/ELK.jpg&quot; width=&quot;380&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next thing I wanted to feed it with some data, good thing someone else added some key=value files to our CI just a few days ago (Thanks Mike).
And I had first real data in to play with in matter of minutes&lt;/p&gt;

&lt;p&gt;That’s was not enough for me, I wanted all the information from my tests.
Seem like the junit-xml output has all the information I wanted.
I hated the idea of running something after the tests are running,
I wanted it to run automatic on any test I’ll run with py.test.&lt;/p&gt;

&lt;p&gt;Took me some time to figure it out which py.test hook fits the best, and here’s how it can be done:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;    &lt;span class=&quot;c1&quot;&gt;# content of conftest.py
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;collect_ec_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
        if we run in EC, collect all data we need
        if not in EC, collect only commit and commit_sha
        :return: dict
        &quot;&quot;&quot;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# lets assume you don&apos;t really want to know what we save in our setup :)
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data_collected&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;send_to_elk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
        send `item` to Logstash port
        :param item: dict
        :return: None
        &quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AF_INET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SOCK_STREAM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TCP_IP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TCP_PORT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Sending to %s:%d&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TCP_IP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TCP_PORT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sendall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dumps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;find_test_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;junit_xml_filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
        flatten all the data from junit based xml file into a list of dicts

        :param junit_xml_filename: the output from py.test --junit-xml
        :return:
        &quot;&quot;&quot;&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;tests_list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;xml_test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;junit_xml_filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;r&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;et&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ElementTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fromstring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xml_test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;et&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;testcase&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attrib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;outcome&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;failure&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;failure&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;skipped&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;skipped&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;failure&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;failure_message&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;failure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;outcome&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;failure&apos;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;skipped&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;skip_message&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;skipped&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attrib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;message&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;outcome&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;skipped&apos;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;error_message&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;outcome&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;error&apos;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;outcome&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;success&apos;&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;outcome&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outcome&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;run_time&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;time&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# time is a built in in Logstash
&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;del&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;time&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;tests_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# filter by group, and merge result
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;cumulative_keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;outcome&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;run_time&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;tests_list_grouped&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groupby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tests_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;classname&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])):&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thing&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;# merge needed values
&lt;/span&gt;                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;outcome&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;outcome&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; &amp;amp; &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;outcome&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;run_time&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;run_time&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;run_time&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

                &lt;span class=&quot;c1&quot;&gt;# overwrite the rest
&lt;/span&gt;                &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cumulative_keys&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;tests_list_grouped&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests_list_grouped&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;pytest_unconfigure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;junit_file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pytest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;option&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xmlpath&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ec_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collect_ec_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;log_dir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;LOG_DEST_DIR&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;./&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;junit_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# if found xml file, send all of it
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;tests_list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;find_test_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;junit_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tests_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ec_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

                &lt;span class=&quot;c1&quot;&gt;# save data to a file
&lt;/span&gt;                &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;job_info%d.json&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;w+&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dumps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sort_keys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                       &lt;span class=&quot;n&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;separators&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;,&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;: &apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

                &lt;span class=&quot;n&quot;&gt;send_to_elk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Just for reference, to show how simple is the logstash configuration, almost untouched:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;input {
        tcp { port =&amp;gt; 3333 type =&amp;gt; &quot;text event&quot;}
        tcp { port =&amp;gt; 3334 type =&amp;gt; &quot;json event&quot; codec =&amp;gt; json_lines {} }
}
filter {
        if [createTime] {
                date {
                        match =&amp;gt; [ &quot;createTime&quot;, &quot;ISO8601&quot; ]
                        target =&amp;gt; &quot;@timestamp&quot;
                }
        }

}
output { elasticsearch { host =&amp;gt; localhost } }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;ELK is a great combo, me like a lot…&lt;/p&gt;

</description>
				<pubDate>Thu, 30 Oct 2014 00:00:00 +0000</pubDate>
				<link>https://fruch.github.io/blog/2014/10/30/ELK-is-fun</link>
				<guid isPermaLink="true">https://fruch.github.io/blog/2014/10/30/ELK-is-fun</guid>
			</item>
		
			<item>
				<title>TheLinuxGameTome is dying, lets save it</title>
				<description>
&lt;p&gt;I’ve read this story on &lt;a href=&quot;http://linux.slashdot.org/story/13/03/26/065223/the-end-is-nigh-for-the-linux-game-tome&quot;&gt;Slashdot&lt;/a&gt;, and thought I might take the database as a django practice build a real web site.
Who want to join me ?&lt;/p&gt;

</description>
				<pubDate>Fri, 05 Apr 2013 00:00:00 +0000</pubDate>
				<link>https://fruch.github.io/blog/2013/04/05/saving-a-linux-happy-peguin</link>
				<guid isPermaLink="true">https://fruch.github.io/blog/2013/04/05/saving-a-linux-happy-peguin</guid>
			</item>
		
	</channel>
</rss>