trace¶

In [ ]:
open sm'_operators
In [ ]:
//// test

open testing

trace¶

trace_level¶

In [ ]:
union trace_level =
    | Verbose
    | Debug
    | Info
    | Warning
    | Critical

read_state¶

In [ ]:
inl read_state () =
    run_target function
        | Rust (Wasm) => fun () =>
            {
                trace_level = None
                repl_start = None
            }
        | Rust (Contract) => fun () =>
            {
                trace_level = None
                repl_start =
                    open rust.rust_operators
                    inl automation = env.get_environment_variable_comptime "AUTOMATION"
                    if automation <>. "True"
                    then None
                    else
                        inl timestamp : u64 = !\($'$"near_sdk::env::block_timestamp()"')
                        timestamp |> i64 |> Some
            }
        | _ => fun () =>
            join
                {
                    trace_level =
                        "TRACE_LEVEL"
                        |> env.get_environment_variable
                        |> reflection.union_try_pick
                    repl_start =
                        inl automation = env.get_environment_variable "AUTOMATION"
                        if automation <>. "True"
                        then None
                        else
                            date_time.now ()
                            |> date_time.ticks
                            |> fun (date_time.timestamp x) => x |> convert
                            |> fun (x : i64) =>
                                backend_switch {
                                    Gleam = fun () =>
                                        backend_switch {
                                            Gleam = fun () =>
                                                global "import gleam/float"
                                                global "import gleam/time/timestamp"
                                        }
                                        $'!x |> timestamp.to_unix_seconds |> float.round' : i64
                                    Fsharp = fun () => x
                                    Python = fun () => x
                                }
                            |> Some
                }

trace_state¶

In [ ]:
type trace_state =
    {
        count : mut i64
        trace_file : mut (string -> ())
        enabled : mut bool
        acc : mut string
        level : mut trace_level
        repl_start : optionm'.option' i64
    }

new_trace_state¶

In [ ]:
let new_trace_state trace_level' =
    inl { repl_start trace_level } = read_state ()
    {
        count = mut 1i64
        trace_file = mut ignore
        enabled = mut true
        acc = mut ""
        level = trace_level |> optionm'.default_value trace_level' |> mut
        repl_start = repl_start |> optionm'.box
    } : trace_state

init_trace_state¶

In [ ]:
inl init_trace_state trace_level : () =
    inl trace_level = trace_level |> optionm'.default_value Verbose
    backend_switch {
        Gleam = fun () =>
            global "fn trace_state () { option.None }"
            $'let trace_state = fn () { case trace_state () { option.None -> !new_trace_state(!trace_level) |> option.Some' : ()
            $'  x -> x' : ()
            $'}}' : ()
        Fsharp = fun () =>
            backend_switch {
                Fsharp = fun () =>
                    global "module TraceState = let mutable trace_state = None"
            }
            fun () =>
                if $'TraceState.trace_state.IsNone' then
                    inl trace_state = new_trace_state trace_level |> optionm'.some'
                    $'TraceState.trace_state <- !trace_state ' : ()
            |> exec_unit
        Python = fun () =>
            global "class TraceState: trace_state = None"
            $'if TraceState.trace_state is None: TraceState.trace_state = !new_trace_state(!trace_level)' : ()
    }

get_trace_state_or_init¶

In [ ]:
inl get_trace_state_or_init trace_level : trace_state =
    init_trace_state trace_level
    backend_switch {
        Gleam = fun () =>
            inl trace_level = trace_level |> optionm'.default_value Verbose
            $'trace_state () |> option.lazy_unwrap(fn () { !new_trace_state(!trace_level) })' : trace_state
        Fsharp = fun () =>
            $'TraceState.trace_state.Value' : trace_state
        Python = fun () =>
            $'TraceState.trace_state' : trace_state
    }

set_trace_level¶

In [ ]:
inl set_trace_level new_level =
    inl ({ level } & trace_state) = get_trace_state_or_init None
    level <- new_level
    backend_switch {
        Gleam = fun () =>
            $'let trace_state = fn () { !(trace_state |> optionm'.some') }' : ()
    }

test_trace_level¶

In [ ]:
inl test_trace_level level : bool =
    inl state = get_trace_state_or_init None
    inl level' = *state.level
    if *state.enabled |> not
    then false
    else
        inl level : i32 = real real_core.union_tag level
        inl level' : i32 = real real_core.union_tag level'
        level >= level'
In [ ]:
//// test
///! gleam
///! fsharp
///! cuda
///! rust
///! typescript
///! python

test_trace_level Critical |> _assert_eq true
test_trace_level Verbose |> _assert_eq true
Debug |> set_trace_level
test_trace_level Verbose |> _assert_eq false
Verbose |> set_trace_level
test_trace_level Verbose |> _assert_eq true
.py output (Python):
{ name = __assert_eq; actual = true; expected = true }
{ name = __assert_eq; actual = true; expected = true }
{ name = __assert_eq; actual = false; expected = false }
{ name = __assert_eq; actual = true; expected = true }


.rs output:
{ name = __assert_eq; actual = true; expected = true }
{ name = __assert_eq; actual = true; expected = true }
{ name = __assert_eq; actual = false; expected = false }
{ name = __assert_eq; actual = true; expected = true }


.ts output:
{ name = __assert_eq; actual = true; expected = true }
{ name = __assert_eq; actual = true; expected = true }
{ name = __assert_eq; actual = false; expected = false }
{ name = __assert_eq; actual = true; expected = true }


.py output:
{ name = __assert_eq; actual = true; expected = true }
{ name = __assert_eq; actual = true; expected = true }
{ name = __assert_eq; actual = false; expected = false }
{ name = __assert_eq; actual = true; expected = true }


.gleam output (Gleam):
{ name = __assert_eq; actual = true; expected = true }
{ name = __assert_eq; actual = true; expected = true }
{ name = __assert_eq; actual = false; expected = false }
{ name = __assert_eq; actual = true; expected = true }


.fsx output:
{ name = __assert_eq; actual = true; expected = true }
{ name = __assert_eq; actual = true; expected = true }
{ name = __assert_eq; actual = false; expected = false }
{ name = __assert_eq; actual = true; expected = true }

trace_raw¶

In [ ]:
inl trace_raw level fn =
    fun () =>
        inl trace_state =
            if level |> test_trace_level |> not
            then None
            else
                inl text = fn ()
                inl ({ count acc } & trace_state) = get_trace_state_or_init None
                fun () =>
                    count <- *count + 1
                |> exec_unit
                open rust
                open rust.rust_operators
                run_target_args (fun () => text, console.write_line) function
                    | Rust (Contract) => fun text, _ =>
                        inl new_acc =
                            if *acc = ""
                            then text
                            elif text = ""
                            then *acc
                            else *acc ++\# text

                        inl chunks =
                            new_acc
                            |> sm'.as_str
                            |> sm'.chars
                            |> rust.from_mut
                            |> iter_collect
                            |> am'.vec_chunks 15000
                            |> am'.vec_map sm'.from_iter

                        inl chunks_len = chunks |> am'.vec_len |> i32

                        if text <>. "" && chunks_len <= 1
                        then acc <- new_acc
                        else
                            acc <- ""
                            chunks
                            |> am'.vec_for_each''' near.log
                    | Rust _ => fun text, _ =>
                        !\\(text, $'\@"println\!(""{}"", $0)"')
                    | _ => fun text, write_line =>
                        text |> write_line

                text |> *trace_state.trace_file
                trace_state |> Some
        backend_switch {
            Gleam = fun () =>
                $'let trace_state = fn () { !(trace_state |> optionm'.box) }' : ()
        }
    |> exec_unit

trace¶

In [ ]:
inl trace (level : trace_level) (text_fn : () -> string) (locals : () -> _) =
    fun () =>
        inl trace_state = get_trace_state_or_init None
        inl time =
            join
                run_target fun target =>
                    match target with
                    | Rust (Contract) => fun () =>
                        open rust.rust_operators
                        open rust
                        inl timestamp = near.block_timestamp ()
                        inl timestamp =
                            match trace_state.repl_start |> optionm'.unbox with
                            | Some repl_start => timestamp - u64 repl_start
                            | None => timestamp
                        inl timestamp_s = timestamp / 1_000_000_000
                        inl s = timestamp_s % 60
                        inl m = (timestamp_s / 60) % 60
                        inl h = (timestamp_s / 3600) % 24
                        inl str : sm'.std_string =
                            !\\((h, m, s), $'$"format\!(\\\"{{:02}}:{{:02}}:{{:02}}\\\", $0, $1, $2)"')
                        str |> sm'.from_std_string
                    | _ => fun () =>
                        match trace_state.repl_start |> optionm'.unbox with
                        | Some repl_start =>
                            inl t =
                                date_time.now ()
                                |> date_time.ticks
                                |> fun (date_time.timestamp x) => x |> convert
                                |> fun (x : i64) =>
                                    backend_switch {
                                        Gleam = fun () =>
                                            global "import gleam/float"
                                            global "import gleam/time/timestamp"
                                            $'!x |> timestamp.to_unix_seconds |> float.round' : i64
                                        Fsharp = fun () => x
                                        Python = fun () => x
                                    }
                                |> flip (-) repl_start
                                |> date_time.time_span
                            date_time.date_time_milliseconds
                                1i32 1i32 1i32
                                (t |> date_time.hours)
                                (t |> date_time.minutes)
                                (t |> date_time.seconds)
                                (t |> date_time.milliseconds)
                        | None => date_time.now ()
                        |> date_time.format (
                            backend_switch {
                                Gleam = fun () => "HH:mm:ss"
                                Fsharp = fun () =>
                                    match target with
                                    | Rust _ => join "hh:mm:ss"
                                    | _ => join "HH:mm:ss"
                                Python = fun () => "%H:%M:%S"
                            }
                        )
        inl level_str =
            join
                inl level_str =
                    level
                    |> reflection.union_to_string
                    |> sm'.to_lower
                    |> sm'.index 0i32
                    |> sm'.format
                run_target function
                | Rust _ => fun () =>
                    open rust
                    open rust.rust_operators
                    inl color : rust.ref sm'.str =
                        match level with
                        | Verbose => !\($'"inline_colorization::color_bright_black"')
                        | Debug => !\($'"inline_colorization::color_bright_blue"')
                        | Info => !\($'"inline_colorization::color_bright_green"')
                        | Warning => !\($'"inline_colorization::color_yellow"')
                        | Critical => !\($'"inline_colorization::color_bright_red"')
                    inl level_str = level_str |> sm'.as_str
                    inl color_reset : rust.ref sm'.str = !\($'"inline_colorization::color_reset"')
                    !\\((color, level_str, color_reset), $'$"format\!(\\\"{{}}{{}}{{}}\\\", $0, $1, $2)"')
                    |> sm'.from_std_string
                | _ => fun () =>
                    inl color =
                        backend_switch {
                            Gleam = fun () =>
                                match level with
                                | Verbose => $'"\\u{001b}[90m"'
                                | Debug => $'"\\u{001b}[94m"'
                                | Info => $'"\\u{001b}[92m"'
                                | Warning => $'"\\u{001b}[93m"'
                                | Critical => $'"\\u{001b}[91m"'
                                : string
                            Fsharp = fun () =>
                                match level with
                                | Verbose => $'"\\u001b[90m"'
                                | Debug => $'"\\u001b[94m"'
                                | Info => $'"\\u001b[92m"'
                                | Warning => $'"\\u001b[93m"'
                                | Critical => $'"\\u001b[91m"'
                                : string
                            Python = fun () =>
                                match level with
                                | Verbose => $'"\\u001b[90m"'
                                | Debug => $'"\\u001b[94m"'
                                | Info => $'"\\u001b[92m"'
                                | Warning => $'"\\u001b[93m"'
                                | Critical => $'"\\u001b[91m"'
                                : string
                        }
                    inl color_reset =
                        backend_switch {
                            Gleam = fun () => $'"\\u{001b}[0m"' : string
                            Fsharp = fun () => join $'"\\u001b[0m"' : string
                            Python = fun () => $'"\\u001b[0m"' : string
                        }
                    color ++# level_str ++# color_reset
        inl text = text_fn ()
        if text = ""
        then ""
        else
            inl locals = locals ()
            join
                inl locals = locals |> sm'.format
                inl count = *trace_state.count
                time ++# " " ++# level_str ++# " #" ++# $count ++# " " ++# text ++# " / " ++# locals
                |> fun x =>
                    join
                        x
                        |> sm'.trim_start []
                        |> sm'.trim_end [ ' '; '/' ]
    |> trace_raw level
In [ ]:
//// test
///! fsharp
///! gleam
///! cuda
///! rust
///! typescript
///! python

trace Debug (fun () => "test1") id
trace Debug (fun () => "test2") id
get_trace_state_or_init None .count
|> fun x => *x
|> _assert_eq 3
.py output (Python):
00:00:00 d #1 test1
00:00:00 d #2 test2
{ name = __assert_eq; actual = 3; expected = 3 }


.gleam output (Gleam):
00:00:00 d #1 test1
00:00:00 d #2 test2
{ name = __assert_eq; actual = 3; expected = 3 }


.rs output:
00:00:00 d #1 test1
00:00:00 d #2 test2
{ name = __assert_eq; actual = 3; expected = 3 }


.ts output:
00:00:00 d #1 test1
00:00:00 d #2 test2
{ name = __assert_eq; actual = 3; expected = 3 }


.py output:
00:00:00 d #1 test1
00:00:00 d #2 test2
{ name = __assert_eq; actual = 3; expected = 3 }


.fsx output:
00:00:00 d #1 test1
00:00:00 d #2 test2
{ name = __assert_eq; actual = 3; expected = 3 }

main¶

In [ ]:
inl main () =
    init_trace_state None
    inl trace level text_fn (locals : () -> string) = trace level text_fn locals
    $'let trace x = !trace x' : ()