Author: alan

  • Prometheus – Quick start for a newbie!

    In the world of oberservability, the winner seems, by-a-mile, to be Prometheus.

    The purpose of this series is to explore how Prometheus works, its different type of metrics, etc.

    1) Quickstart 2) Adding basic metrics to our sample Go application 3) Adding custom metrics to our sample Go application

    Quickstart

    On my Ubuntu box I simply followed the quickstart guide

    curl --location -Ok https://github.com/prometheus/prometheus/releases/download/v3.2.0/prometheus-3.2.0.linux-amd64.tar.gz
    ./promtheus

    The quickstart guide says we can see a list Prometheus’s own metrics (Promception!) by visiting the /metrics URL:

    alan@APZ-OMEN:/mnt/c/Users/alan$ curl -s http://172.22.202.216:9090/metrics | more
    # HELP go_gc_cycles_automatic_gc_cycles_total Count of completed GC cycles generated by the Go runtime. Sourced from /gc/cycles/automatic:gc-cycles.
    # TYPE go_gc_cycles_automatic_gc_cycles_total counter
    go_gc_cycles_automatic_gc_cycles_total 10
    # HELP go_gc_cycles_forced_gc_cycles_total Count of completed GC cycles forced by the application. Sourced from /gc/cycles/forced:gc-cycles.
    # TYPE go_gc_cycles_forced_gc_cycles_total counter
    go_gc_cycles_forced_gc_cycles_total 0
    # HELP go_gc_cycles_total_gc_cycles_total Count of all completed GC cycles. Sourced from /gc/cycles/total:gc-cycles.
    # TYPE go_gc_cycles_total_gc_cycles_total counter
    go_gc_cycles_total_gc_cycles_total 10
    # HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
    # TYPE go_gc_duration_seconds summary
    go_gc_duration_seconds{quantile="0"} 3.3353e-05
    go_gc_duration_seconds{quantile="0.25"} 4.5974e-05
    go_gc_duration_seconds{quantile="0.5"} 0.000163919
    go_gc_duration_seconds{quantile="0.75"} 0.000247898
    go_gc_duration_seconds{quantile="1"} 0.000265798
    go_gc_duration_seconds_sum 0.00141824
    go_gc_duration_seconds_count 10

    The quickstart goes on to say we can query the history of a metric by pasting it into the query box and running execute -> we tried go_gc_cycles_forced_gc_cycles_total and it seems to work !

    One thing we see: the results are annotated with “instance” and “job” labels – this answers our question about how Prometheus handles multiple applications exposing the same metric.

  • Typescript Overloading

    I spent a couple of hours recently trying to solve a problem with overloading in TypeScript only to realise there wasn’t actually a problem at all – I had just completely misunderstood how overloading works !

    Unlike other languages where an overload acts as an “alias” for the implementing method, in TypeScript an overload “replaces” / hides the implementing method – the implementing method becomes inaccessible unless called via an overload signature.

    Example

    I’ll try to show a basic example and then go into more details.

    Imagine, for the sake of this example, an equivalent of “parseInt” (that we could call doParseInt) that takes either a number or a string.

    • If a number is passed we return the number directly.
    • If a string is passed however, a second argument “radix” is required.

    We could code this like:

    // Basic function to test overloading: can be called in two ways
    // value is number (radix not used)
    // value is string (radix required)
    
    function doParseInt(value: (number | string), radix?: number): number {
      if (typeof value === 'number') {
        return value;
      }
      if (typeof value === 'string') {
        return parseInt(value, radix);
      }
      throw new Error(`unexpected value: ${value}`);
    }
    

    We can use it like:

    const val1 = doParseInt(123); // OK
    const val2 = doParseInt('123'); // Error - radix is required if value is string
    const val3 = doParseInt(123, 8); // Error - radix is not used if value is number
    const val4 = doParseInt('123', 10); // OK
    const val5 = doParseInt(123 as (number | string)); // OK
    

    This works but is not great from a type-safety point of view – we have no way of forcing to people to pass a radix if value is string, or likewise from not passing a radix if value is numeric.

    Overloading to the rescue – We add our overload signatures to refine the way we can call the implementing function:

    function doParseInt(value: number): number;
    function doParseInt(value: string, radix: number): number;
    

    Note these are not “functions” – they do not have a body!

    They serve purely as “overload signatures” – method signatures that refine (limit) how we can call the implementing method.

    After adding our signatures, everything seems great except “val5” which no longer compiles – it appears the fact of adding an overload signature has made the original implementing method inaccessible !

    const val1 = doParseInt(123); // OK
    // const val2 = doParseInt('123'); // No longer compiles - great
    // const val3 = doParseInt(123, 8); // Likewise, great
    const val4 = doParseInt('123', 10); // OK
    const val5 = doParseInt(123 as (number | string)); // No longer compiles either .... !
    

    Results in:

    error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'.
    Type 'string' is not assignable to type 'number'.
    

    The problem comes from val5 – we want to be able to call directly the non-overloaded implementation method.

    However, this is not possible in TypeScript – adding a single overload makes the non-overloaded implementation inaccessible.

    To resolve this, we need to simply add the original method signature as an overload signature of itself.

    The final code looks like:

    function doParseInt(value: number): number;
    
    function doParseInt(value: string, radix: number): number;
    
    function doParseInt(value: (number | string), radix?: number): number;
    
    // Basic function to test overloading: can be called in two ways
    // value is number (radix not used)
    // value is string (radix required)
    function doParseInt(value: (number | string), radix?: number): number {
      if (typeof value === 'number') {
        return value;
      }
      if (typeof value === 'string') {
        return parseInt(value, radix);
      }
      throw new Error(`unexpected value: ${value}`);
    }
    

    In hindsight it seems clearly logical – we add overload signatures to refine/specialise the call, and so it doesn’t make much sense to leave the original implementing method available.

    What would have been great would have been an error message more explicit: Implementing function not available if overload signature exists” for example

    This example is slightly contrived: The actual problem was with array signatures (RxJS combineLatest for example) but that will be the subject of my next post.

  • Fitness 09/05

    Started off the morning with two classes: Body Pump and RPM.

    Body Pump 113 (45 mins, lunges + shoulders)

    • Squats – 7.5kg x2 with the bar, 10kg for the presses at the end (no change)
    • Chest – 15kg x2 with the bar, 6kg x2 with the dumb-bells (no change)
    • Back – 7.5kg x2 with the bar (no change)
    • Triceps / Biceps – 6kg x2 with dumb-bells for the biceps (no change)
    • Lunges / Shoulders – 10kg for the presses (no change)

    Spin 86 (30 mins)

  • Fitness 09/01

    Spin (30 mins)

    It’s currently the end the holiday season in France at the moment, so this week my gym is running “video sessions” – no instructor, but we follow the class on the TV.

    BodyPump 113 (45mins)

    I also participated in the evening BodyPump class – edition 113.

    • Squats – 7.5kg x2 with the bar, 10kg for the presses at the end
    • Chest – 15kg x2 with the bar, 6kg x2 with the dumb-bells
    • Back – 7.5kg x2 with the bar – This song is an absolute killer on the forearms !
    • Triceps / Biceps – 6kg x2 with dumb-bells for the biceps
    • Lunges / Shoulders – 10kg for the presses
  • Quick & Dirty Git Mirroring

    A situation that happens often – you’re working on a repository (GitHub for example) also want your commits automatically mirrored to anther repository.

    The obvious solution is to add a second remote, but that means having to constantly remember to push to both remotes. After playing around with the idea of aliases and hooks, I fell upon a little-known Git feature – secondary fetch and push URLs.

    We can add additional fetch and push URLs for a remote by using the reite set-url For example, to add https://my-backup-remote as a remote for the current git remote set-url –add –push origin https://my-backup-remote

    Taking a peek at the .config fileL

    [remote “origin”] url = https://github.com/alanapz/snorlax.git fetch = +refs/heads/:refs/remotes/origin/ pushurl = https://github.com/alanapz/snorlax.git pushurl = \\192.168.1.40\public\projects\snorlax And

    C:\dev\adista\snorlax>git remote show origin

    C:\dev\adista\snorlax>git push origin head -v Pushing to https://github.com/alanapz/snorlax.git To https://github.com/alanapz/snorlax.git = [up to date] head -> master updating local tracking ref ‘refs/remotes/origin/master’ Everything up-to-date Pushing to \192.168.1.40\public\projects\snorlax To \192.168.1.40\public\projects\snorlax = [up to date] head -> master updating local tracking ref ‘refs/remotes/origin/master’ Everything up-to-date

    Notice that fetches are not affected – we fetch from only the fetch URL (perfect – it doesn’t really make sense to fetch from our backup remote).

    C:\dev\adista\snorlax>git fetch -v
    From https://github.com/alanapz/snorlax
     = [up to date]      master     -> origin/master
    

    Quick, easy & dirty !

  • Snorlax – SonarQube reporting tool

    My latest project is a basic SonarQube reporting tool, used to generate e-mail reports on unassigned and open issues by user and project.

    Snorlax is designed do to two things:

    • Notify users periodically of all “overdue” issues (an overdue issue is one that is unresolved since a certain time).
    • Provide managers with a summary report of which users have the most overdue issues, and which projects have the most unassigned issues.

    To Run

    The easiest way is via Docker for Linux:

    docker run -it
            -e SNORLAX_SONAR_URL=*SonarUrl*
            -e SNORLAX_SONAR_TOKEN=*ApiToken*
            -e SNORLAX_SMTP_SERVER=*SmtpServer*
    docker.io/alanmpinder/snorlax:1.0
    

    See README.md for a list of all supported environment variables.

  • Error: WordPress could not establish a secure connection

    So as you can see, I have recently re-setup my blog.

    Everything seemed to go smoothly up until I tried installing a theme (either directly or via file-upload), whereupon I would receive the same error message every time:

    Error: WordPress could not establish a secure connection to WordPress.org

    I wasted a couple of hours upgrading PHP, CURL, OpenSSL as well as my the OpenSSL root before stumbling upon https://wordpress.org/support/topic/error-wordpress-could-not-establish-a-secure-connection-to-wordpress-org/

    This user had exactly the same problem, which he traced to an incompatibility between Curl and SSL with regards to IPV6. Following his advice, I added just before the end of __construct in wp-includes/Requests/Transport/cURL.php the following line:

    curl_setopt($this->handle, CURLOPT_RESOLVE, array("api.wordpress.org:80:198.143.164.251", "api.wordpress.org:443:198.143.164.251"));

    It’s an absolute terrible hack (hard coded IP addresses what could possibly go wrong!) but at least I can install themes on this blog now. So many thanks PeterBB, and eagerly awaiting a resolution to https://meta.trac.wordpress.org/ticket/3090

  • Hello world!

    Welcome to WordPress. This is your first post. Edit or delete it, then start writing!