[{"data":1,"prerenderedAt":306},["ShallowReactive",2],{"$B3SvcJdz-H":3,"pages-links":23,"posts-links":29,"posts-search":58,"blog-log4perl-mixed-screen-appender":129,"decks-for-log4perl-mixed-screen-appender":301,"meta":302},{"id":4,"title":5,"author":6,"description":14,"extension":15,"meta":16,"repository":17,"stem":21,"__hash__":22},"meta\u002Fmeta.yml","bmo.dev",{"name":7,"github":8,"gitlab":9,"email":10,"linkedin":11,"mastodon":12,"bio":13},"William Little","https:\u002F\u002Fgithub.com\u002Fbmodotdev\u002F","https:\u002F\u002Fgitlab.com\u002Fbmodotdev\u002F","L29hqTSwqROvoJ8hMTI2","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fwilliam-e-little-jr\u002F","https:\u002F\u002Fdefcon.social\u002F@bmodotdev","I am a Full Stack Software & DevOps Engineer who loves building and experimenting with Software, Linux, & electronics.\n","A personal blog where I share my thoughts, projects, and anything I might find interesting or helpful.\n","yml",{},{"url":18,"git":19,"branch":20},"https:\u002F\u002Fgitlab.com\u002Fbmodotdev\u002Fbmo.dev\u002F","git@gitlab.com:bmodotdev\u002Fbmo.dev.git","main","meta","MPtcc2KHfBCBy4V4SDhZFIvjyZ_Ba4e-yDnx_Ok_KOs",[24],{"path":25,"extension":26,"title":27,"id":28},"\u002Fabout","md","About","pages\u002Fabout.md",[30,34,38,42,46,50,54],{"path":31,"extension":26,"title":32,"id":33},"\u002Fblog\u002Fconventional-commit-caveats","Conventional Commit Caveats","blog\u002Fblog\u002Fconventional-commit-caveats.md",{"path":35,"extension":26,"title":36,"id":37},"\u002Fblog\u002Fdodging-a-critical-cve-with-zta","Dodging a Critical CVE with ZTA","blog\u002Fblog\u002Fdodging-a-critical-cve-with-zta.md",{"path":39,"extension":26,"title":40,"id":41},"\u002Fblog\u002Flog4perl-mixed-screen-appender","Mixed Output Streams with Log4perl Screen Appender","blog\u002Fblog\u002Flog4perl-mixed-screen-appender.md",{"path":43,"extension":26,"title":44,"id":45},"\u002Fblog\u002Fmake-version","make version","blog\u002Fblog\u002Fmake-version.md",{"path":47,"extension":26,"title":48,"id":49},"\u002Fblog\u002Fpadding-oracle-attacks-rubiks-cow","Padding Oracle Attacks & Rubik’s Cow","blog\u002Fblog\u002Fpadding-oracle-attacks-rubiks-cow.md",{"path":51,"extension":26,"title":52,"id":53},"\u002Fblog\u002Ftracing-signals-in-linux","Tracing Signals in Linux","blog\u002Fblog\u002Ftracing-signals-in-linux.md",{"path":55,"extension":26,"title":56,"id":57},"\u002Fblog\u002Fwhy-are-go-modules-in-my-nodes-modules","Why are Go modules in my node_modules?","blog\u002Fblog\u002Fwhy-are-go-modules-in-my-nodes-modules.md",[59,69,81,90,100,108,117],{"path":55,"title":56,"description":60,"tags":61,"thumbnail":64,"created":68},"Let’s dissect this developer pattern that leads to arbitrary code execution across languages.",[62,63],"go","js",{"sm":65,"md":66,"lg":67},"\u002Fassets\u002Fdavid-mitchell-great-british-baking-show_sm.webp","\u002Fassets\u002Fdavid-mitchell-great-british-baking-show_md.webp","\u002Fassets\u002Fdavid-mitchell-great-british-baking-show_lg.webp","2026-04-07",{"path":35,"title":36,"description":70,"tags":71,"thumbnail":76,"created":80},"Let’s discuss tenets of Zero Trust Architecture, Go, gRPC, and why everyone dodged CVE-2026-33186, right?",[72,73,62,74,75],"awk","cve","grpc","zta",{"sm":77,"md":78,"lg":79},"\u002Fassets\u002Fdodging-the-flyer_sm.webp","\u002Fassets\u002Fdodging-the-flyer_md.webp","\u002Fassets\u002Fdodging-the-flyer_lg.webp","2026-04-02",{"path":47,"title":48,"description":82,"tags":83,"thumbnail":85,"created":89},"In this thought experiment, you’ll learn about cryptographic primitives, combinitorical group theory, and along the way, gain a deeper appreciation for 1999’s film, The Matrix. Oh yeah, and a Cow!",[84],"cryptography",{"sm":86,"md":87,"lg":88},"\u002Fassets\u002Fbournemouth_sm.webp","\u002Fassets\u002Fbournemouth_md.webp","\u002Fassets\u002Fbournemouth_lg.webp","2026-03-06",{"path":43,"title":44,"description":91,"tags":92,"thumbnail":95,"created":99},"Here is how I went about implementing a simple versioning system for my Go project using Conventional Commmits, awk, and make.",[72,93,62,94],"git","semver",{"sm":96,"md":97,"lg":98},"\u002Fassets\u002Flego-pieces_sm.webp","\u002Fassets\u002Flego-pieces_md.webp","\u002Fassets\u002Flego-pieces_lg.webp","2025-11-11",{"path":31,"title":32,"description":101,"tags":102,"thumbnail":103,"created":107},"The Conventional Commmits spec aims to bring structure to commit messages so that we write succint yet meaningful commits. That sounds great, but let’s examine some potential drawbacks.",[93,94],{"sm":104,"md":105,"lg":106},"\u002Fassets\u002Fgit-commit_sm.webp","\u002Fassets\u002Fgit-commit_md.webp","\u002Fassets\u002Fgit-commit_lg.webp","2025-11-07",{"path":39,"title":40,"description":109,"tags":110,"thumbnail":112,"created":116},"Log4perl provides a powerful logging framework, but how can we dynamically and meaninfully use stdout and stderr?",[111],"perl",{"sm":113,"md":114,"lg":115},"\u002Fassets\u002Fperl-latte-onion_100x100.webp","\u002Fassets\u002Fperl-latte-onion_250x250.webp","\u002Fassets\u002Fperl-latte-onion_600x600.webp","2022-02-14",{"path":51,"title":52,"description":118,"tags":119,"thumbnail":124,"created":128},"Signals, or software interrupts, are used to communicate with a process. They could be used to kill a process, restart, or signal a segmentation fault, but how can we know where that signal came from?",[120,121,122,123],"signals","systemtap","strace","linux",{"sm":125,"md":126,"lg":127},"\u002Fassets\u002Ftraffic-light_sm.webp","\u002Fassets\u002Ftraffic-light_md.webp","\u002Fassets\u002Ftraffic-light_lg.webp","2022-02-13",{"id":41,"title":40,"body":130,"created":116,"description":109,"extension":26,"meta":293,"navigation":294,"path":39,"seo":295,"stem":296,"tags":297,"thumbnail":298,"updated":299,"__hash__":300},{"type":131,"value":132,"toc":290},"minimark",[133,163,171,190,200,218,227,255,266,272,278,283,286],[134,135,136,144],"with-caption",{},[137,138,139],"p",{},[140,141],"img",{"alt":142,"src":115,"target":143,"title":142},"“Today’s latte, The Perl Foundation. 25!” by yukop","_blank",[145,146,148],"template",{"v-slot:caption":147},"",[137,149,150,157,158],{},[151,152,156],"a",{"href":153,"rel":154,"target":143},"https:\u002F\u002Fwww.flickr.com\u002Fphotos\u002F22322135@N00\u002F8290092892",[155],"nofollow","“Today’s latte, The Perl Foundation. 25!”"," by ",[151,159,162],{"href":160,"rel":161,"target":143},"https:\u002F\u002Fwww.flickr.com\u002Fphotos\u002F22322135@N00",[155],"yukop",[137,164,165,166,170],{},"Log4perl provides a powerful framework for logging in Perl, based off the now infamous Log4j module.\nWhile it doesn’t support ",[167,168,169],"em",{},"JNDI"," to execute remote code arbitrarily,\nit does just about anything else you could reasonably want it to.",[137,172,173,174,181,182,185,186,189],{},"Log4perl is a modular framework that allows you to append to many different sources,\ne.g. files, sockets, DBI, and of course, directly to the screen.\nWhile using the ",[151,175,178],{"href":176,"rel":177,"target":143},"https:\u002F\u002Fmetacpan.org\u002Fpod\u002FLog::Log4perl::Appender::Screen",[155],[167,179,180],{},"Log::Log4perl::Appender::Screen","\nmodule in a project, I noticed it only supported printing either to ",[167,183,184],{},"STDOUT"," or to ",[167,187,188],{},"STDERR",",\nwhether that log message was FATAL or just INFO:",[191,192,197],"pre",{"className":193,"code":195,"language":196},[194],"language-text","# Legacy - all levels to STDOUT\nlog4perl.appender.Screen.stderr = 0\n\n# Legacy - all levels to STDERR\nlog4perl.appender.Screen.stderr = 1\n","text",[198,199,195],"code",{"__ignoreMap":147},[137,201,202,203,205,206,208,209,211,212,214,215,217],{},"Usually when logging, we reserve ",[167,204,188],{}," for actual errors and the rest goes to ",[167,207,184],{},".\nThis is even more important when it comes to monitoring a script that logs with Log4perl.\nWhen running a script in CI\u002FCD, any output to ",[167,210,188],{}," could cause a pipeline to fail.\nIf Log4perl does not support mixed ",[167,213,184],{},"\u002F",[167,216,188],{},", we lose the ability to detect errors easily in CI\u002FCD pipelines.\nOur debug or info statements could be interpreted as an error, or our errors could be ignored!",[137,219,220,221,226],{},"I created this ",[151,222,225],{"href":223,"rel":224,"target":143},"https:\u002F\u002Fgithub.com\u002Fmschilli\u002Flog4perl\u002Fpull\u002F110",[155],"PR"," to add that feature!\nWe can now have a configuration like below, while still supporting legacy configurations from above:",[191,228,231],{"className":229,"code":230,"language":111,"meta":147,"style":147},"language-perl shiki shiki-themes houston","# New - only ERROR and FATAL to STDERR, the rest to STDOUT\nlog4perl.appender.Screen.stderr.ERROR = 1\nlog4perl.appender.Screen.stderr.FATAL = 1\n",[198,232,233,242,249],{"__ignoreMap":147},[234,235,238],"span",{"class":236,"line":237},"line",1,[234,239,241],{"class":240},"sy89t","# New - only ERROR and FATAL to STDERR, the rest to STDOUT\n",[234,243,245],{"class":236,"line":244},2,[234,246,248],{"class":247},"sLo_3","log4perl.appender.Screen.stderr.ERROR = 1\n",[234,250,252],{"class":236,"line":251},3,[234,253,254],{"class":247},"log4perl.appender.Screen.stderr.FATAL = 1\n",[137,256,257,258,265],{},"Adding that feature was as simple as below,\n",[151,259,262],{"href":260,"rel":261,"target":143},"https:\u002F\u002Fgithub.com\u002Fbmodotdev\u002Flog4perl\u002Fblob\u002Fscreen-appender-stderr-per-log4p_level\u002Flib\u002FLog\u002FLog4perl\u002FAppender\u002FScreen.pm#L34",[155],[167,263,264],{},"Log::Log4perl::Appender::Screen::log",":",[191,267,270],{"className":268,"code":269,"language":196},[194],"my $fh = \\*STDOUT;\nif (ref $self->{stderr}) {\n    $fh = \\*STDERR if $self->{stderr}{ $params{'log4p_level'} }\n                        || $self->{stderr}{ lc $params{'log4p_level'} };\n} elsif ($self->{stderr}) {\n    $fh = \\*STDERR;\n}\n\nprint $fh $params{message};\n",[198,271,269],{"__ignoreMap":147},[137,273,274,275,277],{},"With this change, we would also get new test coverage for both the legacy methods of setting ",[167,276,188],{},"\nand the new method to support mixed output!",[279,280,282],"h2",{"id":281},"update","Update",[137,284,285],{},"This feature was merged into Log4perl June 1, 2022, in version 1.55.",[287,288,289],"style",{},"html pre.shiki code .sy89t, html code.shiki .sy89t{--shiki-default:#EEF0F98F;--shiki-default-font-style:italic}html pre.shiki code .sLo_3, html code.shiki .sLo_3{--shiki-default:#EEF0F9}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":147,"searchDepth":244,"depth":244,"links":291},[292],{"id":281,"depth":244,"text":282},{},true,{"title":40,"description":109},"blog\u002Flog4perl-mixed-screen-appender",[111],{"sm":113,"md":114,"lg":115},"2025-06-01","J_7qElSBqlL3YDJRaezdCwinV5W9_Bwq3xBKJ5aLvhQ",[],{"id":4,"title":5,"author":303,"description":14,"extension":15,"meta":304,"repository":305,"stem":21,"__hash__":22},{"name":7,"github":8,"gitlab":9,"email":10,"linkedin":11,"mastodon":12,"bio":13},{},{"url":18,"git":19,"branch":20},1793313045136]