GO

lspwatch

by whirlwindmola/lspwatch

0 views

Automatic, configurable observability for LSP and MCP servers compilers, datadog, lsp, observability, opentelemetry

monitoringgoSystem Monitoring

lspwatch is a configurable stdin/stdout proxy for the Language Server Protocol (LSP) with built-in observability integrations. lspwatch produces telemetry for the language server and its LSP request/response communication, and exports it to your observability backend.

Shows my svg

lspwatch can calculate and export:

  • Request duration: how long it takes for the language server to respond to code completion, hover, go-to-definition, etc requests from the editor.
  • Language server resident-set size (RSS): how much memory the language server is actively using.

Users can optionally choose to tag metrics with:

  • language_server: name of language server binary (e.g clangd).
  • user: username on the machine.
  • os: operating system.
  • ram: total amount of RAM on the machine.

Why?

If you work on a sufficiently complex typed codebase, you'll find that language support features within modern editors like code completion, diagnostics, suggestions, etc. can become considerably slow. Much of the universally hated sluggishness of code editors is due in large part to these language features. To provide codebase-wide awarness, editors rely on language servers to provide answers to code queries by scanning the codebase and maintaining internal state representations.

To quantify this sluggishness, we can monitor how editors interact with language servers. The duration of an LSP request can tell us how responsive an editor feels. More specifically, this metric can tell us how much (likely idle) time the developer spends waiting for their editor to respond to their edit.

What we essentially have is a real-time, constant, and accurate indicator of developer experience and productivity. I have worked on DevEx teams with access to this kind of data, and it's proven essential for managing the local development experience at scale.

With lspwatch, you get metrics related to the responsiveness of your editor, tagged with contextual details to help with analysis. You can split your metrics by machine configuration, operating system, even down to the user, and more! lspwatch can help you with:

  • Evaluating and improving modularization in your codebase: The nature of the dependency graph will typically impact language server performance.
  • Monitoring the impact of language version upgrades on the coding experience: Any immediate improvements or regressions in language server performance can be noticed and acted on quickly.
  • Identifying potentially misconfigured local development setups or faulty machines.
  • Spotting general usage trends in code editors.

Installation

lspwatch is available only for MacOS and Linux. The easiest way to install it is via a Homebrew tap:

brew install noredeen/tap/lspwatch

Alternatively, you can install executables from the releases page.

Building from source

Prerequisites:

  • Go 1.23.x.
  • make.

Install the project dependencies with make deps, and run sudo make install to build and install lspwatch. If you just want to build the project, you can run make build. To uninstall lspwatch, run sudo make uninstall.

Usage

lspwatch is an executable that transparently stands in place of the language server. lspwatch operates in one of two modes:

  1. command mode: For running one-time language server queries like gopls stats, where the command exits after returning results. Editors often use such queries to gather static metadata.
  2. proxy mode: For long-running language server sessions where LSP messages are continuously exchanged. This is the typical usage of the language server.

lspwatch will automatically choose the correct mode, but you can also specify it using the --mode flag (e.g lspwatch --mode command -- gopls stats). You should never need to do this.

Generally, to use lpswatch for instrumenting your language server, you will need to replace the command your code editor invokes when running the language server. For example, instead of running gopls <args>, your editor should run lspwatch -- gopls <args>. Most LSP-equipped editors will have a way to configure this. Some verified examples are included below, but reference the documentation of your editor or language extension for instructions.

(Golang) Neovim + nvim-lspconfig

/path/to/instrumented_gopls:

#!/bin/bash
lspwatch -- gopls "$@"

init.lua:

gopls = {
  cmd = {
    "/path/to/instrumented_gopls"
  }
}
(Golang) VSCode + vscode-go

/path/to/instrumented_gopls:

#!/bin/bash
lspwatch -- gopls "$@"

.vscode/settings.json:

{
    "go.alternateTools": {
        "gopls": "/path/to/instrumented_gopls"
    }
}

Available metrics

lspwatch offers a set of pre-defined metrics. Some metrics will have tags/attributes which others don't. In your observability backend, every metric name will be prepended with lspwatch..

Options:

  • request.duration (In your observability backend: lspwatch.request.duration)
    • Special tags: method -- name of the LSP request method.
  • server.rss
    • Special tags: None.

Configuration

lspwatch can be configured with a YAML file. Use the --config or -c flag to specify the path. Fields which allow ENV variable expansion can include references to environment variables in the form $ENV_VAR or ${ENV_VAR}.

YAML fieldTypeRequired?ENV variable expansion?Description
projectstringName of the project/repository the language server will operate on. All metrics will be tagged with this value, if provided.
exporterstringEither: datadog or opentelemetry.
env_filestringPath to a .env file containing environment variables relevant to lspwatch.
metrics[]stringThe metrics emitted by lspwatch. Default: all available metrics. Options: request.duration, server.rss.
tags[]stringAdditional tags to include with all metrics. Default: none. Options: user, os, language_server, ram.
metered_requests[]stringMethod names of the LSP requests to monitor/measure. Default: initialize, textDocument/references, textDocument/hover, textDocument/documentSymbols, textDocument/completion, textDocument/diagnostic, textDocument/signatureHelp. Options: LSP docs.
polling_intervalintInterval in seconds for polling language server stats (e.g RSS). Default: 5s. Options: 1 <= t <= 1000.
opentelemetryobjectIf exporter is opentelemtrySee below.
datadogobjectIf exporter is datadogSee below.

opentelemetry

YAML fieldTypeRequired?ENV variable expansion?Description
protocolstringThe protocol used by the OpenTelemetry exporter. Options: grpc, http, file.
directorystringIf protocol is fileThe directory where lspwatch will store OpenTelemetry metrics files.
endpointstringIf protocol is grpc or httpThe OpenTelemetry endpoint, without a path or scheme. Example: localhost:4317.
tlsobjectTLS configuration for the connection to the OpenTelemetry endpoint.
compressionstringCompression scheme for grpc and http requests. Options: gzip.
headersobject; string key-value pairsHeaders to include in the grpc and http requests.
timeoutintgrpc and http request timeout.

datadog

YAML fieldTypeRequired?ENV variable expansion?Description
client_api_keystringValue for Datadog authentication.
client_app_keystringValue for Datadog authentication.
exporter_batch_sizeintThe max number of metrics batched by the exporter before flushing to Datadog.
exporter_batch_timeoutintThe max time between batch flushes to Datadog.
sitestringDatadog site. More info in the Datadog docs.
disable_compressionbooleanDisables HTTP request compression, which is enabled by default.

tls

YAML fieldTypeRequired?ENV variable expansion?Description
insecurebooleanDisables client transport security.
insecure_skip_verifybooleanControls whether a client verifies the server's certificate chain and host name.
ca_filestringPath to a CA file.
cert_filestringPath to a certificate file.
key_filestringPath to a key file.

No config

Running lspwatch without a config file is equivalent to using the following config:

exporter: opentelemetry
opentelemetry:
  protocol: file
  directory: ./

i.e lspwatch will append OpenTelemetry metrics to a file inside the working directory.

[!WARNING]
lspwatch does not yet support output file rotation, so the metrics file will grow in size without bound as metrics get emitted.

Contributing

Contributions are welcomed and a contributing guide is in the works. Refer to the installation section for steps to build from source.

Architecture of lspwatch

Backlog

  • File rotation for logs and OTel local exports.
  • Support for tsserver protocol.
  • New metric: Number of language server crashes.

Install

No configuration available
For more configuration details, refer to the content on the left

Related

Related projects feature coming soon

Will recommend related projects based on sub-categories