{"id":1129,"date":"2013-07-23T22:01:00","date_gmt":"2013-07-23T21:01:00","guid":{"rendered":"https:\/\/www.entropywins.wtf\/blog\/?p=1129"},"modified":"2022-02-08T17:17:47","modified_gmt":"2022-02-08T16:17:47","slug":"profiling-and-logging-in-mediawiki","status":"publish","type":"post","link":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/","title":{"rendered":"Profiling and logging in MediaWiki"},"content":{"rendered":"<p>In this post I first describe the current approaches taken to logging and profiling in MediaWiki, then outline why these are problematic, and finish with a few thoughts on how things can be improved. The problems encountered and solutions proposed are not MediaWiki specific and can be apply to similar situations elsewhere.<\/p>\n<p><strong>The current approach<\/strong><\/p>\n<p>In MediaWiki, profiling, amongst many other things, is done by calling static functions. Sometimes these have the form of global functions such as wfProfileIn, and sometimes they are located in classes, such as SMW\\Profiler::In.<\/p>\n<p>Each usage of wfProfileIn needs to be matched with a closing wfProfileOut. Doing so provides you with information in the execution time between those two calls, if you turned profiling on.<\/p>\n<p>Typically a wfProfileIn is made near the start of some method, and a wfProfileOut is made before each exit point of the method. Bigger methods can have multiple profiling sections. (Though those that do are certainly doing to much.)<\/p>\n<p><strong>Problems<\/strong><\/p>\n<p>Since every usage of methods such as wfProfileIn create a <strong>static<\/strong> <strong>binding<\/strong>, the user of your class does not have the option to not making this profiling call, or to have it be made to a different profiler. You <em>could<\/em> modify or swap out the global profiler, though that is going to create more problems then it solves in any non-trivial system. This also points out that <strong>global state<\/strong> is used, which we all know is bad.<\/p>\n<p>Also see the excellent \u201c<a href=\"http:\/\/kore-nordmann.de\/blog\/0103_static_considered_harmful.html\" target=\"_blank\" rel=\"noopener\">static considered harmful<\/a>\u201d blog post by Kore Nordmann, and read about the aptly named <a href=\"http:\/\/nikic.github.io\/2011\/12\/27\/Dont-be-STUPID-GRASP-SOLID.html\" target=\"_blank\" rel=\"noopener\">STUPID<\/a> acronym.<\/p>\n<p>Concrete places where one runs into the above problems are when writing tests, and when one wants assert the profiling calls are made correctly. Or when you want to enable profiling only in part of your object graph. Or if you have any other usage that is not the default. Global state and static kill the flexibility of your code.<\/p>\n<p>A different type of problem the current approach has is in the form of clutter. Profiling calls and logging calls are made through your business logic, while those two things are clearly quite distinct. This has a number of negative consequences.<\/p>\n<p>First of all, it increases <strong>complexity<\/strong>, by adding more things into methods. Readability and understandability suffer, which in turn increase likelihood of new bugs being introduced and the code rotting further.<\/p>\n<p>Having to put in an opening call to profileIn and matching closing calls to profileOut is a very <strong>error prone<\/strong> process. It\u2019s quite easy to miss an exit point of a method. (Or rather, it is in the MediaWiki codebase, and in most codebases out there. Again, keeping methods appropriately focused eliminates this problem.) It is even easier to introduce new exit points later on, and either not realize one needs to also add a profileOut call, or simply forget about it. And since this code is not being tested due to it being static and global, you are not going to notice the error until someone that tried to profile starts shouting at you.<\/p>\n<p>The clutter problem gets worse as more profiling, logging, debugging calls, and similar are added.<\/p>\n<p>And all of this code gets executed the whole time, and has to be understood by every developer that needs to do some task affecting or affected by this code. In most cases, this is forcing things not relevant to people onto them. Does it make sense to have all these calls to wfProfile, wfLog, wfDebug and so on happen on your production system? As a developer changing some business rule in a method, or even merely understand it, do you want to be forced to hold into account these concerns all of the time while most of the time there would be no such need if concerns where properly separated?<\/p>\n<p><strong>Thoughts on how to make things better<\/strong><\/p>\n<p>MediaWiki should be rewritten from ground up, in Haskell.<\/p>\n<p>More seriously, there are two main approaches that can be used to tackle some of the outlines problems.<\/p>\n<ol>\n<li>One way to achieve great separation between your domain logic and cross cutting concerns such as profiling and logging is to make use of the <strong><a href=\"https:\/\/en.wikipedia.org\/wiki\/Decorator_pattern\" target=\"_blank\" rel=\"noopener\">decorator pattern<\/a><\/strong>.<\/li>\n<\/ol>\n<p><a href=\"https:\/\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2013\/07\/1000px-Proxy_pattern_diagram.svg_.png\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2013\/07\/1000px-Proxy_pattern_diagram.svg_.png\" alt=\"1000px-Proxy_pattern_diagram.svg\" \/><\/a><\/p>\n<p>This is a very simple pattern with lots of similarity to other \u201cwrapping patterns\u201d such as <a href=\"https:\/\/en.wikipedia.org\/wiki\/Adapter_pattern\" target=\"_blank\" rel=\"noopener\">Adapter<\/a> and <a href=\"https:\/\/en.wikipedia.org\/wiki\/Proxy_pattern\" target=\"_blank\" rel=\"noopener\">Proxy<\/a>. Unlike the Adapter pattern, the wrapping class implements the same interface, rather then adapting to another one. The above UML diagram is actually for the Proxy pattern, and at least to me is easier to quickly understand then the Decorator one on Wikipedia. This does not matter much though, since the patterns are structurally identical as far as we are concerned here.<\/p>\n<p>Imagine you have some service object from the domain layer titled \u201cAwesomenessMultiplier\u201d, containing a bunch of business logic. Depending on what kind of public methods this class has, you either create a new abstract class or interface with the name \u201cAwesomenessMultiplier\u201d, after you renamed the original class to something else. Lets say we renamed it to \u201cConcreteAwesomenessMultiplier\u201d. Now you can create a ProfilingAwesomenessMultiplier that extends\/implements AwesomenessMultiplier.<\/p>\n<p>ProfilingAwesomenessMultiplier will be the place where you put all profiling calls. This class has all the public methods specified by AwesomenessMultiplier, after all, it implements\/extends it. In these public methods you can add profiling, logging and whatnot calls as you like, and appropriately forward the call to an object taking care of the real behaviour. This object is stored in a field of type AwesomenessMultiplier.<\/p>\n<p>So typically such a decorating class for logging or profiling will have two fields: a AwesomenessMultiplier and a Logger\/Profiler. Both would be injected via the constructor. If you lack such a Profiler interface, you can put in static calls in the decorator as an intermediate step. It\u2019ll get rid of the clutter problem, and decrease the static binding problem. The later will however still be in your decorator, and presumably in lots of other parts of your application. It is thus well worthwhile to create the trivial abstractions needed to get rid of this.<\/p>\n<p>You can have a LoggingAwesomenessMultiplier wrap a AwesomenessMultiplier, and have that whole thing wrapped by a ProfilingAwesomenessMultiplier. And then pass it around through your system without any of it knowing anything about logging, profiling, or the use of decorators to hide those concerns.<\/p>\n<ol>\n<li>Proper dependency injection<\/li>\n<\/ol>\n<p>In case one needs to make calls that are not at the start\/end of public methods, using decorators does not work nicely. You could somewhat modify the approach by using inheritance so you can place calls around protected methods as well. That however breaks encapsulation and might cause more problems then it solves.<\/p>\n<p>You are thus forced to have some logging, profile, etc, code in the same class with your business logic. It thus becomes very important the concerns outlined in this post are addressed as best as possible, as unlike with the decorator approach, they\u2019ll be in your face the whole time.<\/p>\n<p>Step one is getting rid of those nasty static calls relying on global state. Enter <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dependency_injection\" target=\"_blank\" rel=\"noopener\">dependency injection<\/a>.<\/p>\n<p>Inject a thing implementing a Logger or a Profiler interface in the constructor of your object and stuff it into a field. Your code then calls $this-&gt;logger-&gt;log() rather then wfLog().<\/p>\n<p>When creating such interfaces, keep the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Interface_segregation_principle\" target=\"_blank\" rel=\"noopener\">Interface Segregation Principle<\/a> in mind. They should not contain everything that could possibly be related to logging. In case of PHP development, also consider the <a href=\"https:\/\/github.com\/php-fig\/fig-standards\/blob\/master\/accepted\/PSR-3-logger-interface.md\" target=\"_blank\" rel=\"noopener\">PSR-3 standard<\/a> which has been adopted by a bunch of frameworks already.<\/p>\n<p>In case of doing calls such as profileIn that need matching profileOut closing calls, do separate this on the method level. Rather then doing this<\/p>\n<pre>public function multiplyAwesomeness() {\n    profileIn( __METHOD__ );\n\n    if ( foo() ) {\n        $result = bar();\n        profileOut( __METHOD__ );\n        return $result;\n    }\n\n    $result = 'baz';\n    profileOut( __METHOD__ );\n    return $result;\n}<\/pre>\n<p>Consider doing the below:<\/p>\n<pre>public function multiplyAwesomeness() {\n    profileIn( __METHOD__ );\n    $result = $this-&gt;doAwesomenessMultiplication();\n    profileOut( __METHOD__ );\n\n    return $result;\n}\n\nprotected function doAwesomenessMultiplication() {\n    if ( foo() ) {\n        return bar();\n    }\n\n    return 'baz';\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>In this post I first describe the current approaches taken to logging and profiling in MediaWiki, then outline why these&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[7],"tags":[465,156],"class_list":["post-1129","post","type-post","status-publish","format-standard","hentry","category-programming","tag-logging","tag-mediawiki"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Profiling and logging in MediaWiki - Blog of Jeroen De Dauw<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Profiling and logging in MediaWiki - Blog of Jeroen De Dauw\" \/>\n<meta property=\"og:description\" content=\"In this post I first describe the current approaches taken to logging and profiling in MediaWiki, then outline why these&hellip;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/\" \/>\n<meta property=\"og:site_name\" content=\"Blog of Jeroen De Dauw\" \/>\n<meta property=\"article:published_time\" content=\"2013-07-23T21:01:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-02-08T16:17:47+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2013\/07\/1000px-Proxy_pattern_diagram.svg_.png\" \/>\n<meta name=\"author\" content=\"Jeroen\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/JeroenDeDauw\" \/>\n<meta name=\"twitter:site\" content=\"@JeroenDeDauw\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jeroen\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/\"},\"author\":{\"name\":\"Jeroen\",\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7\"},\"headline\":\"Profiling and logging in MediaWiki\",\"datePublished\":\"2013-07-23T21:01:00+00:00\",\"dateModified\":\"2022-02-08T16:17:47+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/\"},\"wordCount\":1283,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7\"},\"image\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2013\/07\/1000px-Proxy_pattern_diagram.svg_.png\",\"keywords\":[\"Logging\",\"MediaWiki\"],\"articleSection\":[\"Programming\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/\",\"url\":\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/\",\"name\":\"Profiling and logging in MediaWiki - Blog of Jeroen De Dauw\",\"isPartOf\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2013\/07\/1000px-Proxy_pattern_diagram.svg_.png\",\"datePublished\":\"2013-07-23T21:01:00+00:00\",\"dateModified\":\"2022-02-08T16:17:47+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#primaryimage\",\"url\":\"https:\/\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2013\/07\/1000px-Proxy_pattern_diagram.svg_.png\",\"contentUrl\":\"https:\/\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2013\/07\/1000px-Proxy_pattern_diagram.svg_.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.entropywins.wtf\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Profiling and logging in MediaWiki\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#website\",\"url\":\"https:\/\/www.entropywins.wtf\/blog\/\",\"name\":\"Entropy Wins\",\"description\":\"A blog on Software Architecture, Design and Craftsmanship\",\"publisher\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.entropywins.wtf\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7\",\"name\":\"Jeroen\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g\",\"caption\":\"Jeroen\"},\"logo\":{\"@id\":\"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/image\/\"},\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/jeroendedauw\/\",\"https:\/\/x.com\/https:\/\/twitter.com\/JeroenDeDauw\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Profiling and logging in MediaWiki - Blog of Jeroen De Dauw","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/","og_locale":"en_US","og_type":"article","og_title":"Profiling and logging in MediaWiki - Blog of Jeroen De Dauw","og_description":"In this post I first describe the current approaches taken to logging and profiling in MediaWiki, then outline why these&hellip;","og_url":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/","og_site_name":"Blog of Jeroen De Dauw","article_published_time":"2013-07-23T21:01:00+00:00","article_modified_time":"2022-02-08T16:17:47+00:00","og_image":[{"url":"https:\/\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2013\/07\/1000px-Proxy_pattern_diagram.svg_.png","type":"","width":"","height":""}],"author":"Jeroen","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/JeroenDeDauw","twitter_site":"@JeroenDeDauw","twitter_misc":{"Written by":"Jeroen","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#article","isPartOf":{"@id":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/"},"author":{"name":"Jeroen","@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7"},"headline":"Profiling and logging in MediaWiki","datePublished":"2013-07-23T21:01:00+00:00","dateModified":"2022-02-08T16:17:47+00:00","mainEntityOfPage":{"@id":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/"},"wordCount":1283,"commentCount":0,"publisher":{"@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7"},"image":{"@id":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#primaryimage"},"thumbnailUrl":"https:\/\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2013\/07\/1000px-Proxy_pattern_diagram.svg_.png","keywords":["Logging","MediaWiki"],"articleSection":["Programming"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/","url":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/","name":"Profiling and logging in MediaWiki - Blog of Jeroen De Dauw","isPartOf":{"@id":"https:\/\/www.entropywins.wtf\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#primaryimage"},"image":{"@id":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#primaryimage"},"thumbnailUrl":"https:\/\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2013\/07\/1000px-Proxy_pattern_diagram.svg_.png","datePublished":"2013-07-23T21:01:00+00:00","dateModified":"2022-02-08T16:17:47+00:00","breadcrumb":{"@id":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#primaryimage","url":"https:\/\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2013\/07\/1000px-Proxy_pattern_diagram.svg_.png","contentUrl":"https:\/\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2013\/07\/1000px-Proxy_pattern_diagram.svg_.png"},{"@type":"BreadcrumbList","@id":"https:\/\/www.entropywins.wtf\/blog\/2013\/07\/23\/profiling-and-logging-in-mediawiki\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.entropywins.wtf\/blog\/"},{"@type":"ListItem","position":2,"name":"Profiling and logging in MediaWiki"}]},{"@type":"WebSite","@id":"https:\/\/www.entropywins.wtf\/blog\/#website","url":"https:\/\/www.entropywins.wtf\/blog\/","name":"Entropy Wins","description":"A blog on Software Architecture, Design and Craftsmanship","publisher":{"@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.entropywins.wtf\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/4e2ef14f2ca7dc3a0ac137d1692b66b7","name":"Jeroen","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d62e6b5b8e332335cf17854fac850d9c70ba367c4692872613c3110ebd4e009b?s=96&d=mm&r=g","caption":"Jeroen"},"logo":{"@id":"https:\/\/www.entropywins.wtf\/blog\/#\/schema\/person\/image\/"},"sameAs":["https:\/\/www.linkedin.com\/in\/jeroendedauw\/","https:\/\/x.com\/https:\/\/twitter.com\/JeroenDeDauw"]}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p74TBF-id","jetpack-related-posts":[{"id":2856,"url":"https:\/\/www.entropywins.wtf\/blog\/2022\/02\/08\/using-psr3-monolog-in-mediawiki\/","url_meta":{"origin":1129,"position":0},"title":"Using PSR-3 Monolog in MediaWiki","author":"Jeroen","date":"2022-02-08","format":false,"excerpt":"Since a few years, you can use the PSR-3 LoggerInterface in MediaWiki to log messages. But how can you tell MediaWiki to use a specific logger? In this technical post, we will look at how to use a Monolog logger in MediaWiki. If you have used Monolog before, you presumably\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1172,"url":"https:\/\/www.entropywins.wtf\/blog\/2014\/01\/02\/mediawiki-extensions-to-define-their-mediawiki-compatibility\/","url_meta":{"origin":1129,"position":1},"title":"MediaWiki extensions to define their MediaWiki compatibility","author":"Jeroen","date":"2014-01-02","format":false,"excerpt":"Over the past year support for real dependency management has been gradually added to MediaWiki and selected extensions. This support being based on the Composer software. While extensions have been able to specify their dependencies for a while, such as PHP libraries and other extensions, they where not able to\u2026","rel":"","context":"In \"composer\"","block_context":{"text":"composer","link":"https:\/\/www.entropywins.wtf\/blog\/tag\/composer\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":787,"url":"https:\/\/www.entropywins.wtf\/blog\/2010\/04\/23\/mediawiki-all-time-contributor-25\/","url_meta":{"origin":1129,"position":2},"title":"MediaWiki all time contributor #25","author":"Jeroen","date":"2010-04-23","format":false,"excerpt":"With my last commit I made yesterday, I entered the top 25 all time MediaWiki contributors. The below screenshot from Ohloh shows and my current commit count :) I estimate It'll take me just over 2 months to enter the top 20, as I'm currently committing roughly 150 changes a\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"Jeroen De Dauw @ #25 in the all time MediaWiki contributor list","src":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2010\/04\/25.gif?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2010\/04\/25.gif?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2010\/04\/25.gif?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":2941,"url":"https:\/\/www.entropywins.wtf\/blog\/2025\/08\/20\/why-you-should-use-mediawiki-lts-versions\/","url_meta":{"origin":1129,"position":3},"title":"Why You Should Skip MediaWiki 1.44","author":"Jeroen","date":"2025-08-20","format":false,"excerpt":"Or: Why you should stop worrying and love the LTS releases. TL;DR: Stick to MediaWiki 1.43 LTS, avoid MediaWiki 1.44, 1.45, and 1.46. There are two major MediaWiki releases every year, and every fourth such release gets Long Term Support (LTS). Two consistent approaches to upgrading MediaWiki are to upgrade\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/www.entropywins.wtf\/blog\/category\/software\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2025\/08\/MediaWikiLTS.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2025\/08\/MediaWikiLTS.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2025\/08\/MediaWikiLTS.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2025\/08\/MediaWikiLTS.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2025\/08\/MediaWikiLTS.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2025\/08\/MediaWikiLTS.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":604,"url":"https:\/\/www.entropywins.wtf\/blog\/2009\/12\/13\/5o-mediawiki-committer\/","url_meta":{"origin":1129,"position":4},"title":"#50 MediaWiki committer","author":"Jeroen","date":"2009-12-13","format":false,"excerpt":"Yay - I just entered the top 50 of MediaWiki committers, based on commit count over the last 5 years :p Next stop: #42 :)","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"MediaWiki committer #50: Jeroen De Dauw","src":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2009\/12\/mwcommitter50.GIF?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2009\/12\/mwcommitter50.GIF?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2009\/12\/mwcommitter50.GIF?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":1081,"url":"https:\/\/www.entropywins.wtf\/blog\/2011\/05\/07\/new-mediawiki-extension-ratings\/","url_meta":{"origin":1129,"position":5},"title":"New MediaWiki extension: Ratings","author":"Jeroen","date":"2011-05-07","format":false,"excerpt":"A few weeks back I started work on a new MediaWiki extension to provide decent rating functionality. The reason: I got sick of all the crappy rating extensions out there and decided to write one that both works and has sane code. The new extension is called \"Ratings\". The Ratings\u2026","rel":"","context":"In &quot;Programming&quot;","block_context":{"text":"Programming","link":"https:\/\/www.entropywins.wtf\/blog\/category\/programming\/"},"img":{"alt_text":"MediaWiki Ratings extension","src":"https:\/\/i0.wp.com\/www.entropywins.wtf\/blog\/wp-content\/uploads\/2011\/04\/Mediawiki-ratings.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/posts\/1129","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/comments?post=1129"}],"version-history":[{"count":3,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/posts\/1129\/revisions"}],"predecessor-version":[{"id":2857,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/posts\/1129\/revisions\/2857"}],"wp:attachment":[{"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/media?parent=1129"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/categories?post=1129"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.entropywins.wtf\/blog\/wp-json\/wp\/v2\/tags?post=1129"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}