# Autometrics List
A command that lists all functions that have the "autometrics" annotation.
The aim is to use this binary as a quick static analyzer that returns from a
codebase the complete list of functions that are annotated to be
autometricized.
The analysis is powered by [Tree-sitter](https://tree-sitter.github.io), and
all the specific logic is contained in [Tree-sitter queries](./runtime/queries)
that are specific for each language implementation.
## Quickstart
Use the installer script to pull the latest version directly from Github
(change `VERSION` accordingly):
```console
And run the binary
```bash
# Make sure that `~/.cargo/bin` is in your `PATH`
am_list list -l rs /path/to/project/root
```
## Current state and known issues
### Language support table
In the following table, having the "detection" feature means that `am_list`
returns the exact same labels as the ones you would need to use in PromQL to
look at the metrics. In a nutshell,
"[Autometrics](https://github.com/autometrics-dev) compliance".
[Rust](https://github.com/autometrics-dev/autometrics-rs) | ✅ | ✅
[Typescript](https://github.com/autometrics-dev/autometrics-ts) | ✅ | ⚠️
[Go](https://github.com/autometrics-dev/autometrics-go) | ⚠️ | ✅
[Python](https://github.com/autometrics-dev/autometrics-py) | ❌ | ❌
[C#](https://github.com/autometrics-dev/autometrics-cs) | ❌ | ❌
### Typescript
#### Module tracking
This tool cannot track modules "accurately" (meaning "the module label is
exactly what autometrics will report"), because autometrics-ts uses the path of
the source in the JS-compiled bundle to report the module. The compilation and
bundling happens after `am_list` looks at the code so it cannot be accurate.
This means the module reporting for typescript is bound to be a "best effort"
attempt to be useful.
The other difficulty encountered when using a static analysis tool with autometrics-ts is that the
instrumentation can happen anywhere, as the wrapper function call can use an imported symbol as its argument:
``` typescript
import { exec } from 'child_process'
import { autometrics } from '@autometrics/autometrics'
const instrumentedExec = autometrics(exec)
// use instrumentedExec everywhere instead of exec
```
In order to report the locus of _function definition_ as the module, we would
need to include both:
- a complete import resolution step, to figure out the origin module of the
instrumented function (`child_process` in the example), and
- a dependency inspection step, to figure out the path to the instrumented
function definition _within_ the dependency (`lib/child_process.js` in the
[node source code](https://github.com/nodejs/node/blob/main/lib/child_process.js))
This is impractical and error-prone to implement these steps accurately, so
instead we only try to detect imports when they are explicitely imported in the
same file, and we will only report the function module as the imported module
(not the path to the file it is defined in). Practically that means that for
this example:
``` typescript
// in src/router/index.ts
import { exec } from 'child_process'
import { origRoute as myRoute } from '../handlers'
import { autometrics } from '@autometrics/autometrics'
const instrumentedExec = autometrics(exec)
const instrumentedRoute = autometrics(myRoute)
// use instrumentedExec everywhere instead of exec
```
`am_list` will report 2 functions:
- `{"function": "exec", "module": "ext://child_process"}`: using `ext://`
protocol to say the module is non-local
- `{"function": "origRoute", "module": "handlers"}`: even if `myRoute` is
re-exported from `../handlers/my/routes/index.ts`, we do not go look into what
`handlers` did to expose `origRoute`; also, the alias is resolved.