diff --git a/build.mill b/build.mill index a6d85b9..d5abd59 100644 --- a/build.mill +++ b/build.mill @@ -1,3 +1,7 @@ +import mill.scalalib.publish.Developer +import mill.scalalib.publish.VersionControl +import mill.scalalib.publish.License +import mill.scalalib.publish.PomSettings import mill.eval.Evaluator import smithy4s.codegen.LSP import com.goyeau.mill.scalafix.ScalafixModule @@ -37,14 +41,42 @@ object slsSmithy extends CommonScalaModule with Smithy4sModule { ) } +object profilingRuntime extends CommonScalaModule with PublishModule { + def ivyDeps = Agg( + ivy"io.pyroscope:agent:2.1.2", + ivy"org.typelevel::cats-effect:3.6.3", + ivy"org.typelevel::otel4s-sdk:0.13.1", + ivy"org.typelevel::otel4s-sdk-exporter:0.13.1", + ivy"org.typelevel::otel4s-experimental-metrics:0.7.0", + ivy"org.typelevel::otel4s-instrumentation-metrics:0.13.1" + ) + + def pomSettings: T[PomSettings] = PomSettings( + description = "A runtime with pyroscope profiling and OpenTelemetry tracing", + url = "", + licenses = Seq(License.`MPL-2.0`), + organization = "org.scala.abusers", + versionControl = VersionControl.github("simple-scala-tooling", "simple-language-server"), + developers = Seq( + Developer("rochala", "Jędrzej Rochala", url = "https://github.com/rochala") + ) + ) + + def publishVersion: T[String] = "0.0.1-SNAPSHOT" +} + object sls extends CommonScalaModule { def mainClass = Some("org.scala.abusers.sls.SimpleScalaServer") - def moduleDeps: Seq[JavaModule] = Seq(slsSmithy) + def moduleDeps: Seq[JavaModule] = Seq(slsSmithy, profilingRuntime) + + override def forkArgs: T[Seq[String]] = Seq( + "-Dcats.effect.trackFiberContext=true" + ) def ivyDeps = Agg( - ivy"org.typelevel::cats-effect:3.6.2", + ivy"org.typelevel::cats-effect:3.6.3", ivy"co.fs2::fs2-io:3.13.0-M2", ivy"io.scalaland::chimney:1.8.1", ivy"io.scalaland::chimney-java-collections:1.8.1", @@ -52,10 +84,14 @@ object sls extends CommonScalaModule { ivy"ch.qos.logback:logback-classic:1.4.14", ivy"com.lihaoyi::os-lib:0.11.4", ivy"org.polyvariant.smithy4s-bsp::bsp4s:0.5.0", - ivy"org.scalameta:mtags-interfaces:1.5.1", + ivy"org.scalameta:mtags-interfaces:1.6.3", ivy"com.evolution::scache:5.1.2", ivy"org.typelevel::cats-parse:1.1.0", - ivy"io.get-coursier:interface:1.0.28" + ivy"io.get-coursier:interface:1.0.28", + ) + + def javacOptions = Seq( + "-Dotel.service.name=simple-language-server", ) object test extends ScalaTests { diff --git a/otel4s/docker-compose.yaml b/otel4s/docker-compose.yaml new file mode 100644 index 0000000..9528bcf --- /dev/null +++ b/otel4s/docker-compose.yaml @@ -0,0 +1,63 @@ +services: + otel-collector: + image: otel/opentelemetry-collector-contrib + command: [--config=/etc/otel-collector-config.yaml] + volumes: + - "./opentelemetry/otel-collector-config.yaml:/etc/otel-collector-config.yaml" + ports: + - "8888:8888" # Prometheus metrics exposed by the collector + - "8889:8889" # Prometheus exporter metrics + - "4317:4317" # OTLP gRPC receiver + - "4318:4318" # OTLP http receiver + networks: + - static-network + + tempo: + image: grafana/tempo + command: [ "-config.file=/etc/tempo.yaml" ] + volumes: + - "./tempo/tempo.yaml:/etc/tempo.yaml" + ports: + - "3200:3200" + - "4317" + - "4318" + networks: + - static-network + + prometheus: + image: prom/prometheus:latest + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--web.enable-remote-write-receiver' + volumes: + - "./prometheus/prometheus.yaml:/etc/prometheus/prometheus.yml" + ports: + - "9090:9090" + networks: + - static-network + + pyroscope: + image: grafana/pyroscope + ports: + - "4040:4040" + networks: + - static-network + + grafana: + image: grafana/grafana + restart: unless-stopped + environment: + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + volumes: + - "./grafana/datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml" + - "./grafana/dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml" + - "./grafana/dashboards/:/var/lib/grafana/dashboards/" + ports: + - "3000:3000" + networks: + - static-network + +networks: + static-network: diff --git a/otel4s/grafana/dashboards.yaml b/otel4s/grafana/dashboards.yaml new file mode 100644 index 0000000..40289c1 --- /dev/null +++ b/otel4s/grafana/dashboards.yaml @@ -0,0 +1,24 @@ +apiVersion: 1 + +providers: + # an unique provider name. Required + - name: 'dashboards' + # Org id. Default to 1 + orgId: 1 + # name of the dashboard folder. + folder: '' + # folder UID. will be automatically generated if not specified + folderUid: '' + # provider type. Default to 'file' + type: file + # disable dashboard deletion + disableDeletion: false + # how often Grafana will scan for changed dashboards + updateIntervalSeconds: 10 + # allow updating provisioned dashboards from the UI + allowUiUpdates: true + options: + # path to dashboard files on disk. Required when using the 'file' type + path: /var/lib/grafana/dashboards + # use folder names from filesystem to create folders in Grafana + foldersFromFilesStructure: true diff --git a/otel4s/grafana/dashboards/application.json b/otel4s/grafana/dashboards/application.json new file mode 100644 index 0000000..2e25a73 --- /dev/null +++ b/otel4s/grafana/dashboards/application.json @@ -0,0 +1,4495 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "A dashboard to visualize Cats Effect runtime metrics. ", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": 1, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 59, + "panels": [], + "title": "Tracing", + "type": "row" + }, + { + "datasource": { + "type": "tempo", + "uid": "cezfsujm3zrb4d" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 50, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointShape": "circle", + "pointSize": { + "fixed": 10 + }, + "pointStrokeWidth": 1, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "show": "points" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 55, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "mapping": "auto", + "series": [ + {} + ], + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "tempo", + "uid": "cezfsujm3zrb4d" + }, + "filters": [ + { + "id": "f1a5cec4", + "operator": "=", + "scope": "span" + } + ], + "limit": 500, + "metricsQueryType": "range", + "queryType": "traceqlSearch", + "refId": "A", + "spss": 5, + "tableType": "traces" + } + ], + "title": "Traces", + "transformations": [ + { + "id": "partitionByValues", + "options": { + "fields": [ + "Name" + ], + "keepFields": false, + "naming": { + "asLabels": false + } + } + } + ], + "type": "xychart" + }, + { + "datasource": { + "type": "tempo", + "uid": "cezfsujm3zrb4d" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Trace Service" + }, + "properties": [ + { + "id": "custom.width", + "value": 159 + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 56, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Start time" + } + ] + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "tempo", + "uid": "cezfsujm3zrb4d" + }, + "filters": [ + { + "id": "9d3c8809", + "operator": "=", + "scope": "span" + } + ], + "limit": 500, + "metricsQueryType": "range", + "queryType": "traceqlSearch", + "refId": "A", + "spss": 5, + "tableType": "traces" + } + ], + "title": "Traces Table", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Name": false, + "Service": true, + "Trace Service": true, + "traceIdHidden": true + }, + "includeByName": {}, + "indexByName": {}, + "orderByMode": "manual", + "renameByName": { + "traceIdHidden": "" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "tempo", + "uid": "cezfsujm3zrb4d" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 58, + "options": { + "spanFilters": { + "criticalPathOnly": false, + "matchesOnly": false, + "serviceNameOperator": "=", + "spanNameOperator": "=", + "tags": [ + { + "id": "b810943f-e7c", + "operator": "=" + } + ] + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "tempo", + "uid": "cezfsujm3zrb4d" + }, + "filters": [ + { + "id": "02551e08", + "operator": "=", + "scope": "span" + }, + { + "id": "span-name", + "isCustomValue": false, + "operator": "=", + "scope": "span", + "tag": "name", + "value": [], + "valueType": "string" + }, + { + "id": "status", + "isCustomValue": false, + "operator": "=", + "scope": "intrinsic", + "tag": "status", + "valueType": "keyword" + } + ], + "limit": 20, + "metricsQueryType": "range", + "query": "${traceId}", + "queryType": "traceql", + "refId": "A", + "tableType": "traces" + } + ], + "title": "Trace", + "type": "traces" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 44, + "panels": [], + "title": "JVM Metrics - Garbage Collection", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 7, + "x": 0, + "y": 24 + }, + "id": 43, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "rate(jvm_gc_duration_seconds_count[1m])", + "fullMetaSearch": false, + "includeNullMetadata": false, + "instant": false, + "interval": "", + "legendFormat": "{{jvm_gc_action}} - {{jvm_gc_name}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Collections", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 8, + "x": 7, + "y": 24 + }, + "id": 45, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "rate(jvm_gc_duration_seconds_sum{}[1m])/rate(jvm_gc_duration_seconds_count{}[1m])", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Pause Durations", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 9, + "x": 15, + "y": 24 + }, + "id": 51, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "jvm_memory_used_after_last_gc_bytes", + "instant": false, + "interval": "", + "legendFormat": "{{jvm_memory_pool_name}} - {{jvm_memory_type}}", + "range": true, + "refId": "A" + } + ], + "title": "Memory Used After Last GC", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 40, + "panels": [], + "title": "JVM Metrics - Classloading", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 0, + "y": 35 + }, + "id": 46, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "builder", + "expr": "jvm_class_loaded_total", + "instant": false, + "interval": "", + "legendFormat": "loaded", + "range": true, + "refId": "A" + } + ], + "title": "Classes loaded", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 8, + "y": 35 + }, + "id": 47, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "delta(jvm_class_count[1m])", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "delta-1m", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Class delta", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 0, + "y": 44 + }, + "id": 53, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "jvm_class_unloaded_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "interval": "", + "legendFormat": "unloaded", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Classes unloaded", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 8, + "y": 44 + }, + "id": 54, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "jvm_class_count", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "delta-1m", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Currently Loaded Classes", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 53 + }, + "id": 39, + "panels": [], + "title": "JVM Metrics - CPU", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 0, + "y": 54 + }, + "id": 41, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "jvm_cpu_count", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "CPU Count", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 9, + "x": 4, + "y": 54 + }, + "id": 49, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "jvm_cpu_recent_utilization_ratio", + "instant": false, + "legendFormat": "process", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "avg_over_time(jvm_cpu_recent_utilization_ratio[15m])", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "process-15m", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "description": "The percent of time spent on Garbage Collection over all CPUs assigned to the JVM process.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 11, + "x": 13, + "y": 54 + }, + "id": 48, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "sum by(job) (rate(jvm_gc_duration_seconds_count{job=\"$job\"}[1m])) / on(job) jvm_cpu_count", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "GC Pressure", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 62 + }, + "id": 38, + "panels": [], + "title": "JVM Metrics - Memory", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 63 + }, + "id": 52, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "jvm_memory_used_bytes{jvm_memory_type=\"non_heap\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{jvm_memory_pool_name}} - used", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "jvm_memory_committed_bytes{jvm_memory_type=\"non_heap\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{jvm_memory_pool_name}} - commited", + "range": true, + "refId": "D", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "jvm_memory_limit_bytes{jvm_memory_type=\"non_heap\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{jvm_memory_pool_name}} - limit", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "JVM Memory Pool Non Heap", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 63 + }, + "id": 50, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "jvm_memory_used_bytes{jvm_memory_type=\"heap\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{jvm_memory_pool_name}} - used", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "jvm_memory_committed_bytes{jvm_memory_type=\"heap\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{jvm_memory_pool_name}} - commited", + "range": true, + "refId": "D", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "jvm_memory_limit_bytes{jvm_memory_type=\"heap\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{jvm_memory_pool_name}} - limit", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "JVM Memory Pool Heap", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 75 + }, + "id": 37, + "panels": [], + "title": "JVM Metrics - Thread", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 25, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 7, + "x": 0, + "y": 76 + }, + "id": 42, + "options": { + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "right", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "jvm_thread_count", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{jvm_thread_state}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Thread Count", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 85 + }, + "id": 8, + "panels": [], + "title": "CPU starvation", + "type": "row" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 0, + "y": 86 + }, + "id": 13, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "The [starvation checker](https://typelevel.org/cats-effect/docs/core/starvation-and-tuning) is a runtime assertion that any latency higher than the threshold (by default, 100 milliseconds) is bad and deserves a warning. The common causes:\n- Blocking tasks\n- Compute-bound work\n- Not enough CPUs\n- Too many threads\n- Burst credit contention\n- Process contention\n\n", + "mode": "markdown" + }, + "pluginVersion": "12.1.1", + "title": "Overview", + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "description": "The current clock drift", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "fieldMinMax": false, + "mappings": [], + "max": 100, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "light-orange", + "value": 10 + }, + { + "color": "red", + "value": 50 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 7, + "y": 86 + }, + "id": 21, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^current$/", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "editorMode": "code", + "exemplar": false, + "expr": "cats_effect_runtime_cpu_starvation_clock_drift_current_milliseconds{job=\"${job:value}\"}", + "hide": false, + "instant": true, + "legendFormat": "current", + "range": false, + "refId": "A" + } + ], + "title": "Clock drift [current]", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "B", + "mappings": [ + { + "fieldName": "total", + "handlerKey": "max" + } + ] + } + } + ], + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "description": "The current number of time CPU starvation has occurred", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 11, + "y": 86 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "editorMode": "code", + "expr": "increase(cats_effect_runtime_cpu_starvation_count_total{job=\"${job:value}\"}[$range])", + "instant": false, + "legendFormat": "Starvations", + "range": true, + "refId": "A" + } + ], + "title": "Starvations [$range]", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "description": "The current (last) and max (since the launch) observed clock drift in milliseconds", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 17, + "y": 86 + }, + "id": 10, + "options": { + "legend": { + "calcs": [ + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "editorMode": "code", + "exemplar": false, + "expr": "cats_effect_runtime_cpu_starvation_clock_drift_current_milliseconds{job=\"${job:value}\"}", + "instant": false, + "legendFormat": "Current", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "cats_effect_runtime_cpu_starvation_clock_drift_max_milliseconds{job=\"${job:value}\"}", + "hide": false, + "instant": false, + "legendFormat": "Max", + "range": true, + "refId": "B" + } + ], + "title": "Clock drift", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 94 + }, + "id": 2, + "panels": [], + "title": "Work-Stealing Thread Pool | Compute", + "type": "row" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 95 + }, + "id": 7, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "This dashboard evaluates the utilization of compute threads in the [Cats Effect](https://github.com/typelevel/cats-effect) runtime:\n- Thread pool utilization - monitor the utilization of the worker threads\n- Blocking and searching threads - identify bottlenecks by tracking blocked and searching threads\n- Fiber management - understand fiber enqueue trends\n", + "mode": "markdown" + }, + "pluginVersion": "12.1.1", + "title": "Overview", + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The number of worker thread instances backing the work-stealing thread pool (WSTP)", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-blue", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 12, + "y": 95 + }, + "id": 1, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "exemplar": false, + "expr": "cats_effect_runtime_wstp_compute_thread_count", + "format": "time_series", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A", + "useBackend": false + } + ], + "title": "Worker threads", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The number of active worker thread instances currently executing fibers on the compute thread pool", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 16, + "y": 95 + }, + "id": 19, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "cats_effect_runtime_wstp_compute_thread_active_count{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\"}", + "format": "table", + "instant": true, + "legendFormat": "active", + "range": false, + "refId": "A" + } + ], + "title": "Active threads", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "B", + "mappings": [ + { + "fieldName": "total", + "handlerKey": "max" + } + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The number of worker thread instances that can run blocking actions on the compute thread pool", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 20, + "y": 95 + }, + "id": 20, + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^blocked$/", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "cats_effect_runtime_wstp_compute_thread_blocked_count{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\"}", + "format": "time_series", + "instant": true, + "legendFormat": "blocked", + "range": false, + "refId": "A" + } + ], + "title": "Blocking threads", + "transformations": [ + { + "id": "configFromData", + "options": { + "configRefId": "B", + "mappings": [ + { + "fieldName": "total", + "handlerKey": "max" + } + ] + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The number of active worker thread instances currently executing fibers on the compute thread pool", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 103 + }, + "id": 3, + "options": { + "legend": { + "calcs": [ + "min", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum(cats_effect_runtime_wstp_compute_thread_active_count{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\"})", + "instant": false, + "legendFormat": "Active", + "range": true, + "refId": "A" + } + ], + "title": "Active", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The number of worker thread instances that can run blocking actions on the compute thread pool", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 103 + }, + "id": 5, + "options": { + "legend": { + "calcs": [ + "min", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum(cats_effect_runtime_wstp_compute_thread_blocked_count{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\"})", + "instant": false, + "legendFormat": "Blocking", + "range": true, + "refId": "A" + } + ], + "title": "Blocking", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The number of worker thread instances currently searching for fibers to steal from other worker threads", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 111 + }, + "id": 4, + "options": { + "legend": { + "calcs": [ + "min", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum(cats_effect_runtime_wstp_compute_thread_searching_count{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\"})", + "instant": false, + "legendFormat": "Searching", + "range": true, + "refId": "A" + } + ], + "title": "Searching", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The total number of fibers enqueued on all local queues", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 111 + }, + "id": 6, + "options": { + "legend": { + "calcs": [ + "min", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum(increase(cats_effect_runtime_wstp_compute_fiber_enqueued_count{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\"}[$range]))", + "instant": false, + "legendFormat": "Enqueued", + "range": true, + "refId": "A" + } + ], + "title": "Enqueued fibers [$range]", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The number of fibers which are currently asynchronously suspended", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 119 + }, + "id": 31, + "options": { + "legend": { + "calcs": [ + "min", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum(increase(cats_effect_runtime_wstp_compute_fiber_suspended_count{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\"}[$range]))", + "legendFormat": "Suspended", + "range": true, + "refId": "A" + } + ], + "title": "Suspended fibers [$range]", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 127 + }, + "id": 22, + "panels": [], + "title": "Work-Stealing Thread Pool | Worker Thread", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The total number of events that happend to the worker thread", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 128 + }, + "id": 23, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum (increase(cats_effect_runtime_wstp_worker_thread_event_count_total{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\", worker_index=~\"${wstp_worker_index:regex}\"}[$range])) by (worker_index, thread_event)", + "legendFormat": "Worker {{ worker_index }} - {{ thread_event }}", + "range": true, + "refId": "A" + } + ], + "title": "Events per state [$range]", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The total amount of time in nanoseconds that this worker thread has been parked", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ns" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 12, + "x": 12, + "y": 128 + }, + "id": 24, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum (increase(cats_effect_runtime_wstp_worker_thread_idle_duration_nanoseconds_total{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\", worker_index=~\"${wstp_worker_index:regex}\"}[$range])) by (worker_index)", + "legendFormat": "Worker {{ worker_index }}", + "range": true, + "refId": "A" + } + ], + "title": "Idle (parked) duration [$range]", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 139 + }, + "id": 11, + "panels": [], + "title": "Work-Stealing Thread Pool | Local Queue", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The number of currently enqueued fibers", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 140 + }, + "id": 14, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum(cats_effect_runtime_wstp_worker_localqueue_fiber_enqueued_count{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\", worker_index=~\"${wstp_worker_index:regex}\"}) by (worker_index)", + "instant": false, + "legendFormat": "Queue {{ worker_index }}", + "range": true, + "refId": "A" + } + ], + "title": "Enqueued fibers", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The total number of fibers enqueued during the lifetime of the local queue", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 140 + }, + "id": 15, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum(increase(cats_effect_runtime_wstp_worker_localqueue_fiber_count_total{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\", worker_index=~\"${wstp_worker_index:regex}\"}[$range])) by (worker_index)", + "instant": false, + "legendFormat": "Queue {{ worker_index }}", + "range": true, + "refId": "A" + } + ], + "title": "Total fibers [$range]", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The total number of stolen fibers by other worker threads", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 150 + }, + "id": 18, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum(increase(cats_effect_runtime_wstp_worker_localqueue_fiber_count_total{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\", worker_index=~\"${wstp_worker_index:regex}\"}[$range])) by (worker_index)", + "instant": false, + "legendFormat": "Queue {{ worker_index }}", + "range": true, + "refId": "A" + } + ], + "title": "Stolen fibers [$range]", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The total number of successful steal attempts by other worker threads", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 150 + }, + "id": 17, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum(increase(cats_effect_runtime_wstp_worker_localqueue_fiber_steal_attempt_count_total{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\", worker_index=~\"${wstp_worker_index:regex}\"}[$range])) by (worker_index)", + "instant": false, + "interval": "", + "legendFormat": "Queue {{ worker_index }}", + "range": true, + "refId": "A" + } + ], + "title": "Successful steal attempts [$range]", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The total number of fibers spilled over to the external queue", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 159 + }, + "id": 16, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum(increase(cats_effect_runtime_wstp_worker_localqueue_fiber_spillover_count_total{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\", worker_index=~\"${wstp_worker_index:regex}\"}[$range])) by (worker_index)", + "instant": false, + "legendFormat": "Queue {{ worker_index }}", + "range": true, + "refId": "A" + } + ], + "title": "Spilled over fibers [$range]", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 169 + }, + "id": 26, + "panels": [], + "title": "Work-Stealing Thread Pool | Timer Heap", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The time in nanoseconds till the next due to fire", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ns" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 170 + }, + "id": 27, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum (cats_effect_runtime_wstp_worker_timerheap_next_due_nanoseconds{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\", worker_index=~\"${wstp_worker_index:regex}\"}) by (worker_index)", + "legendFormat": "Timer {{worker_index}}", + "range": true, + "refId": "A" + } + ], + "title": "Next due", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The current number of the outstanding timers that remain to be executed", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 170 + }, + "id": 28, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum (cats_effect_runtime_wstp_worker_timerheap_outstanding_count{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\", worker_index=~\"${wstp_worker_index:regex}\"}) by (worker_index)", + "legendFormat": "Timer {{worker_index}}", + "range": true, + "refId": "A" + } + ], + "title": "Outstanding timers", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The total number of timers per state", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 179 + }, + "id": 30, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum (increase(cats_effect_runtime_wstp_worker_timerheap_timer_count_total{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\", worker_index=~\"${wstp_worker_index:regex}\"}[$range])) by (worker_index, timer_state)", + "legendFormat": "Timer {{worker_index}} - {{ timer_state }}", + "range": true, + "refId": "A" + } + ], + "title": "Timers [$range]", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The total number of times the heap packed itself to remove canceled timers", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 179 + }, + "id": 29, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum (increase(cats_effect_runtime_wstp_worker_timerheap_packed_count_total{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\", worker_index=~\"${wstp_worker_index:regex}\"}[$range])) by (worker_index)", + "legendFormat": "Timer {{worker_index}}", + "range": true, + "refId": "A" + } + ], + "title": "Packed [$range]", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 188 + }, + "id": 32, + "panels": [], + "title": "Work-Stealing Thread Pool | Poller", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The current number of outstanding operations per category", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 189 + }, + "id": 33, + "options": { + "legend": { + "calcs": [ + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum by (worker_index, poller_operation) (cats_effect_runtime_wstp_worker_poller_operation_outstanding_count{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\", worker_index=~\"${wstp_worker_index:regex}\"})", + "instant": false, + "legendFormat": "Poller {{ worker_index }} - {{ poller_operation }}", + "range": true, + "refId": "A" + } + ], + "title": "Outstanding operations", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The total number of operations per category and outcome", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 189 + }, + "id": 36, + "options": { + "legend": { + "calcs": [ + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "editorMode": "code", + "expr": "sum by (worker_index, poller_operation, poller_opration_status) (increase(cats_effect_runtime_wstp_worker_poller_operation_count_total{job=\"${job:value}\", pool_id=\"${wstp_pool:value}\", worker_index=~\"${wstp_worker_index:regex}\"}[$range]))", + "instant": false, + "legendFormat": "Poller {{ worker_index }} - {{ poller_operation }}", + "range": true, + "refId": "A" + } + ], + "title": "Total operations [$range]", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [ + "cats-effect" + ], + "templating": { + "list": [ + { + "current": { + "text": "prometheus", + "value": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "description": "The Prometheus instance to use", + "label": "Data Source", + "name": "prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "current": { + "text": "otel-collector", + "value": "otel-collector" + }, + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "definition": "label_values(cats_effect_runtime_cpu_starvation_clock_drift_max_milliseconds,job)", + "includeAll": false, + "label": "Job", + "name": "job", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(cats_effect_runtime_cpu_starvation_clock_drift_max_milliseconds,job)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "0", + "value": "0" + }, + "datasource": { + "type": "prometheus", + "uid": "${prometheus}" + }, + "definition": "label_values(cats_effect_runtime_wstp_compute_thread_count,pool_id)", + "label": "WSTP pool", + "name": "wstp_pool", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(cats_effect_runtime_wstp_compute_thread_count,pool_id)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "f13f44c8-69b1-48ae-a55c-90f49179283c" + }, + "definition": "label_values(cats_effect_runtime_wstp_worker_thread_event_count_total,worker_index)", + "description": "Which worker to show", + "includeAll": true, + "label": "WSTP worker", + "multi": true, + "name": "wstp_worker_index", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(cats_effect_runtime_wstp_worker_thread_event_count_total,worker_index)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "10m", + "value": "10m" + }, + "label": "Range", + "name": "range", + "options": [ + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "2m", + "value": "2m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": true, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + } + ], + "query": "1m, 2m, 5m, 10m, 30m", + "type": "custom" + }, + { + "current": { + "text": "", + "value": "" + }, + "label": "Trace ID", + "name": "traceId", + "options": [], + "query": "", + "type": "custom" + } + ] + }, + "time": { + "from": "now-3h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Application", + "uid": "fe8ds2gwa0tmof", + "version": 15 +} diff --git a/otel4s/grafana/datasources.yaml b/otel4s/grafana/datasources.yaml new file mode 100644 index 0000000..84da070 --- /dev/null +++ b/otel4s/grafana/datasources.yaml @@ -0,0 +1,60 @@ +# Configuration file version +apiVersion: 1 + +# List of data sources to insert/update depending on what's +# available in the database. +datasources: + # Sets the name you use to refer to + # the data source in panels and queries. + - id: 1 + uid: f13f44c8-69b1-48ae-a55c-90f49179283c + orgId: 1 + name: prometheus + type: prometheus + typeName: Prometheus + typeLogoUrl: "/public/app/plugins/datasource/prometheus/img/prometheus_logo.svg" + access: proxy + url: http://prometheus:9090 + user: '' + database: '' + basicAuth: false + basicAuthUser: '' + isDefault: false + jsonData: + httpMethod: POST + readOnly: false + - id: 2 + uid: dezft048pwcg0d + orgId: 1 + type: grafana-pyroscope-datasource + name: Pyroscope + typeLogoUrl: "/public/plugins/grafana-pyroscope-datasource/img/grafana_pyroscope_icon.svg" + access: proxy + url: http://pyroscope:4040 + user: '' + database: '' + basicAuth: false + basicAuthUser: '' + isDefault: false + jsonData: + pdcInjected: false + readOnly: false + - id: 3 + uid: cezfsujm3zrb4d + orgId: 1 + name: Tempo + type: tempo + typeLogoUrl: "/public/plugins/tempo/img/tempo_logo.svg" + access: proxy + url: http://tempo:3200 + user: '' + database: '' + basicAuth: false + basicAuthUser: '' + withCredentials: false + isDefault: false + jsonData: + pdcInjected: false + tracesToProfiles: + datasourceUid: dezft048pwcg0d + readOnly: false diff --git a/otel4s/opentelemetry/otel-collector-config.yaml b/otel4s/opentelemetry/otel-collector-config.yaml new file mode 100644 index 0000000..f1dfa5d --- /dev/null +++ b/otel4s/opentelemetry/otel-collector-config.yaml @@ -0,0 +1,33 @@ +receivers: + otlp: + protocols: # enable OpenTelemetry HTTP Protocol receiver + http: + endpoint: 0.0.0.0:4318 + grpc: + endpoint: 0.0.0.0:4317 + +exporters: + otlp: + endpoint: tempo:4317 + tls: + insecure: true + + prometheus: + endpoint: 0.0.0.0:8889 + send_timestamps: true + +processors: + batch: + timeout: 10s + + +service: + pipelines: + traces: + receivers: [otlp] + processors: [batch] + exporters: [otlp] + metrics: + receivers: [otlp] + processors: [batch] + exporters: [prometheus] diff --git a/otel4s/prometheus/prometheus.yaml b/otel4s/prometheus/prometheus.yaml new file mode 100644 index 0000000..76c9090 --- /dev/null +++ b/otel4s/prometheus/prometheus.yaml @@ -0,0 +1,28 @@ +global: + scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. + evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. + # scrape_timeout is set to the global default (10s). + +# Alertmanager configuration +alerting: + alertmanagers: + - static_configs: + - targets: + # - alertmanager:9093 + +# Load rules once and periodically evaluate them according to the global 'evaluation_interval'. +rule_files: +# - "first_rules.yml" +# - "second_rules.yml" + +# A scrape configuration containing exactly one endpoint to scrape: +# Here it's Prometheus itself. +scrape_configs: + # The job name is added as a label `job=` to any timeseries scraped from this config. + - job_name: "prometheus" + static_configs: + - targets: ["localhost:9090"] + + - job_name: "otel-collector" + static_configs: + - targets: ["otel-collector:8889"] diff --git a/otel4s/tempo/tempo.yaml b/otel4s/tempo/tempo.yaml new file mode 100644 index 0000000..c17bd0f --- /dev/null +++ b/otel4s/tempo/tempo.yaml @@ -0,0 +1,44 @@ +server: + http_listen_port: 3200 + +distributor: + receivers: # this configuration will listen on all ports and protocols that tempo is capable of. + otlp: + protocols: + http: + endpoint: 0.0.0.0:4318 + grpc: + endpoint: 0.0.0.0:4317 + +metrics_generator: + + registry: + external_labels: + source: tempo + cluster: docker-compose + storage: + path: /tmp/tempo/generator/wal + remote_write: + - url: http://prometheus:9090/api/v1/write + send_exemplars: true + + processor: + span_metrics: + dimensions: + - service.name + - span.name + - span.kind + - status.code + +storage: + trace: + backend: local # backend configuration to use + wal: + path: /tmp/tempo/wal # where to store the the wal locally + local: + path: /tmp/tempo/blocks + +overrides: + defaults: + metrics_generator: + processors: [span-metrics] # enables metrics generator diff --git a/profilingRuntime/src/org/scala/abusers/profiling/runtime/ProfilingExecutionContext.scala b/profilingRuntime/src/org/scala/abusers/profiling/runtime/ProfilingExecutionContext.scala new file mode 100644 index 0000000..5f2033b --- /dev/null +++ b/profilingRuntime/src/org/scala/abusers/profiling/runtime/ProfilingExecutionContext.scala @@ -0,0 +1,49 @@ +package org.scala.abusers.profiling.runtime + +import io.pyroscope.vendor.one.profiler.AsyncProfiler +import org.typelevel.otel4s.sdk.context.Context +import org.typelevel.otel4s.sdk.context.TraceContext +import org.typelevel.otel4s.sdk.trace.SdkContextKeys + +import scala.concurrent.ExecutionContext + +object ProfilingExecutionContext { + + def wrapExecutionContext( + ec: ExecutionContext, + profiler: AsyncProfiler, + localContext: ThreadLocal[Context], + ): ExecutionContext = + new ExecutionContext { + def execute(runnable: Runnable): Unit = + + ec.execute(new Runnable { + val ctx = localContext.get() + def run(): Unit = { + + val spanOpt = ctx + .get(SdkContextKeys.SpanContextKey) + .filter(_.isValid) + .map { ctx => + TraceContext( + ctx.traceId, + ctx.spanId, + ctx.isSampled, + ) + } + + spanOpt.foreach { span => + profiler.setTracingContext(span.spanId.toLong(signed = false), 0) + } + + try + runnable.run() + finally + spanOpt.foreach(_ => profiler.setTracingContext(0, 0)) + } + }) + + def reportFailure(cause: Throwable): Unit = ec.reportFailure(cause) + } + +} diff --git a/profilingRuntime/src/org/scala/abusers/profiling/runtime/ProfilingIOApp.scala b/profilingRuntime/src/org/scala/abusers/profiling/runtime/ProfilingIOApp.scala new file mode 100644 index 0000000..290b14a --- /dev/null +++ b/profilingRuntime/src/org/scala/abusers/profiling/runtime/ProfilingIOApp.scala @@ -0,0 +1,102 @@ +package org.scala.abusers.profiling.runtime + +import cats.effect.kernel.Resource +import cats.effect.unsafe.IORuntime +import cats.effect.unsafe.IORuntimeBuilder +import cats.effect.ExitCode +import cats.effect.IO +import cats.effect.IOApp +import cats.effect.IOLocal +import cats.effect.SyncIO +import cats.syntax.all.* +import io.pyroscope.http.Format +import io.pyroscope.javaagent.config.Config as PyroscopeConfig +import io.pyroscope.javaagent.EventType +import io.pyroscope.javaagent.PyroscopeAgent +import io.pyroscope.PyroscopeAsyncProfiler +import org.typelevel.otel4s.context.LocalProvider +import org.typelevel.otel4s.experimental.metrics._ +import org.typelevel.otel4s.metrics.Meter +import org.typelevel.otel4s.sdk.context.Context +import org.typelevel.otel4s.sdk.exporter.otlp.autoconfigure.OtlpExportersAutoConfigure +import org.typelevel.otel4s.sdk.OpenTelemetrySdk +import org.typelevel.otel4s.trace.Tracer +import cats.effect.std.Console +import org.typelevel.otel4s.instrumentation.ce.IORuntimeMetrics +import org.typelevel.otel4s.metrics.MeterProvider + +object ProfilingIOAppSettings { + lazy val isEnabled: Boolean = + sys.env.get("SLS_PROFILING").contains("true") || sys.props.get("sls.profiling").contains("true") +} + +trait ProfilingIOApp extends IOApp { + private lazy val profiler = PyroscopeAsyncProfiler.getAsyncProfiler() + + given console: Console[IO] + + private given localCtx: IOLocal[Context] = IOLocal[Context](Context.root) + .syncStep(100) + .flatMap( + _.leftMap(_ => + new Error( + "Failed to initialize the local context of the IOLocalContextStorageProvider." + ) + ).liftTo[SyncIO] + ) + .unsafeRunSync() + + private val threadLocal = localCtx.unsafeThreadLocal() + + private lazy val _runtime = { + IORuntimeBuilder() + .transformCompute(ec => ProfilingExecutionContext.wrapExecutionContext(ec, profiler, threadLocal)) + .transformBlocking(ec => ProfilingExecutionContext.wrapExecutionContext(ec, profiler, threadLocal)) + .build() + } + + override protected def runtime: IORuntime = + if ProfilingIOAppSettings.isEnabled then _runtime else super.runtime + + def program(using meter: Meter[IO], tracer: Tracer[IO]): Resource[IO, Unit] + def applicationName: String + + override def run(args: List[String]): IO[ExitCode] = + OpenTelemetrySdk + .autoConfigured[IO](_ + .addExportersConfigurer(OtlpExportersAutoConfigure[IO]) + .addTracerProviderCustomizer((builder, _) => builder.addSpanProcessor(new ProfilingSpanProcessor)) + ) + .flatTap(_ => registerPyroscope()) + .use { autoConfigured => + val sdk = autoConfigured.sdk + given MeterProvider[IO] = sdk.meterProvider + + val app = for { + given Meter[IO] <- sdk.meterProvider.get(applicationName).toResource + given Tracer[IO] <- sdk.tracerProvider.get(applicationName).toResource + _ <- IORuntimeMetrics.register[IO](runtime.metrics, IORuntimeMetrics.Config.default) + _ <- RuntimeMetrics.register[IO] + _ <- program + } yield () + + app.useForever + } + .as(ExitCode.Success) + + private def registerPyroscope(): Resource[IO, Unit] = { + val acquire = IO.whenA(ProfilingIOAppSettings.isEnabled)( IO.delay { + PyroscopeAgent.start( + PyroscopeConfig + .Builder() + .setApplicationName(applicationName) + .setProfilingEvent(EventType.ITIMER) + .setFormat(Format.JFR) + .setServerAddress("http://localhost:4040") // Refactor in the future to be configurable + .build() + ) + }) + + Resource.eval(acquire).void + } +} diff --git a/profilingRuntime/src/org/scala/abusers/profiling/runtime/ProfilingOps.scala b/profilingRuntime/src/org/scala/abusers/profiling/runtime/ProfilingOps.scala new file mode 100644 index 0000000..ede7777 --- /dev/null +++ b/profilingRuntime/src/org/scala/abusers/profiling/runtime/ProfilingOps.scala @@ -0,0 +1,15 @@ +package org.scala.abusers.profiling.runtime + +import cats.effect.IO +import org.typelevel.otel4s.trace.Span +import org.typelevel.otel4s.trace.SpanOps + +object ProfilingOps { + extension (ops: SpanOps[IO]) { + def profilingUse[A](f: Span[IO] => IO[A]): IO[A] = + if ProfilingIOAppSettings.isEnabled then ops.use(span => (IO.cede *> f(span)).guarantee(IO.cede)) + else ops.use(f) + + inline def profilingSurround[A](fa: IO[A]): IO[A] = profilingUse(_ => fa) + } +} diff --git a/profilingRuntime/src/org/scala/abusers/profiling/runtime/ProfilingSpanProcessor.scala b/profilingRuntime/src/org/scala/abusers/profiling/runtime/ProfilingSpanProcessor.scala new file mode 100644 index 0000000..bb43fa8 --- /dev/null +++ b/profilingRuntime/src/org/scala/abusers/profiling/runtime/ProfilingSpanProcessor.scala @@ -0,0 +1,28 @@ +package org.scala.abusers.profiling.runtime + +import cats.effect.IO +import org.typelevel.otel4s.sdk.trace.data.SpanData +import org.typelevel.otel4s.sdk.trace.processor.SpanProcessor +import org.typelevel.otel4s.sdk.trace.processor.SpanProcessor.OnEnd +import org.typelevel.otel4s.sdk.trace.processor.SpanProcessor.OnStart +import org.typelevel.otel4s.sdk.trace.SpanRef +import org.typelevel.otel4s.trace.SpanContext +import org.typelevel.otel4s.Attribute + +class ProfilingSpanProcessor extends SpanProcessor[IO] { + + override def name: String = "ProfilingSpanProcessor" + + override def onStart: OnStart[IO] = new OnStart[IO] { + override def apply(parentContext: Option[SpanContext], span: SpanRef[IO]): IO[Unit] = { + val spanIdStr = span.context.spanIdHex + span.addAttributes(Seq(Attribute("pyroscope.profile.id", spanIdStr))) + } + } + + override def onEnd: OnEnd[IO] = new OnEnd[IO] { + override def apply(span: SpanData): IO[Unit] = IO.unit + } + + override def forceFlush: IO[Unit] = IO.unit +} diff --git a/sls/src/org/scala/abusers/sls/BspClient.scala b/sls/src/org/scala/abusers/sls/BspClient.scala index 6c6a0ce..1f5e9b8 100644 --- a/sls/src/org/scala/abusers/sls/BspClient.scala +++ b/sls/src/org/scala/abusers/sls/BspClient.scala @@ -14,8 +14,8 @@ import cats.syntax.all.* import com.comcast.ip4s.* import fs2.io.* import fs2.io.net.Network -import jsonrpclib.Endpoint import jsonrpclib.fs2.{lsp => jsonrpclibLsp, *} +import jsonrpclib.Endpoint import smithy4sbsp.bsp4s.BSPCodecs def makeBspClient(path: String, channel: FS2Channel[IO], report: String => IO[Unit]): Resource[IO, BuildServer] = @@ -25,7 +25,10 @@ def makeBspClient(path: String, channel: FS2Channel[IO], report: String => IO[Un fs2.Stream .eval(IO.never) .concurrently( - socket.reads.through(jsonrpclibLsp.decodeMessages).evalTap(m => report(m.toString)).through(channel.inputOrBounce) + socket.reads + .through(jsonrpclibLsp.decodeMessages) + .evalTap(m => report(m.toString)) + .through(channel.inputOrBounce) ) .concurrently(channel.output.through(jsonrpclibLsp.encodeMessages).through(socket.writes)) .compile @@ -47,8 +50,6 @@ def bspClientHandler(lspClient: SlsLanguageClient[IO], diagnosticManager: Diagno .serverEndpoints( new BuildClient[IO] { - - def onBuildLogMessage(input: LogMessageParams): IO[Unit] = IO.unit // we want some logging to file here def onBuildPublishDiagnostics(input: PublishDiagnosticsParams): IO[Unit] = diff --git a/sls/src/org/scala/abusers/sls/BspStateManager.scala b/sls/src/org/scala/abusers/sls/BspStateManager.scala index 6a2c030..1fba201 100644 --- a/sls/src/org/scala/abusers/sls/BspStateManager.scala +++ b/sls/src/org/scala/abusers/sls/BspStateManager.scala @@ -53,7 +53,7 @@ class BspStateManager( def importBuild = for { - _ <- lspClient.logMessage("Starting build import.") // in the future this should be a task with progress + _ <- lspClient.logMessage("Starting build import.") // in the future this should be a task with progress importedBuild <- getBuildInformation(bspServer) _ <- bspServer.generic.buildTargetCompile(CompileParams(targets = importedBuild.map(_.buildTarget.id).toList)) _ <- targets.set(importedBuild) @@ -113,7 +113,10 @@ class BspStateManager( state.getOrElse(uri, throw new IllegalStateException("Get should always be called after didOpen")) } - def didOpen(client: SlsLanguageClient[IO], params: lsp.DidOpenTextDocumentParams)(using SynchronizedState): IO[Unit] = { + def didOpen( + client: SlsLanguageClient[IO], + params: lsp.DidOpenTextDocumentParams, + )(using SynchronizedState): IO[Unit] = { val uri = URI.create(params.textDocument.uri) sourcesToTargets.evalUpdate(state => for { diff --git a/sls/src/org/scala/abusers/sls/ComputationQueue.scala b/sls/src/org/scala/abusers/sls/ComputationQueue.scala index b594529..9d0b0fe 100644 --- a/sls/src/org/scala/abusers/sls/ComputationQueue.scala +++ b/sls/src/org/scala/abusers/sls/ComputationQueue.scala @@ -1,7 +1,7 @@ package org.scala.abusers.sls -import cats.effect.IO import cats.effect.std.Semaphore +import cats.effect.IO sealed trait SynchronizedState @@ -11,12 +11,10 @@ trait ComputationQueue { } class ComputationQueueImpl(semaphore: Semaphore[IO]) extends ComputationQueue { - def synchronously[A](computation: SynchronizedState ?=> IO[A]): IO[A] = { - semaphore.permit.use(_ => computation) - } + def synchronously[A](computation: SynchronizedState ?=> IO[A]): IO[A] = + semaphore.permit.surround(computation) } object ComputationQueue { - def instance: IO[ComputationQueue] = - Semaphore[IO](1).map(ComputationQueueImpl.apply) + def instance: IO[ComputationQueue] = Semaphore[IO](1).map(ComputationQueueImpl.apply) } diff --git a/sls/src/org/scala/abusers/sls/ErrOutConsole.scala b/sls/src/org/scala/abusers/sls/ErrOutConsole.scala new file mode 100644 index 0000000..0291838 --- /dev/null +++ b/sls/src/org/scala/abusers/sls/ErrOutConsole.scala @@ -0,0 +1,18 @@ +package org.scala.abusers.sls + +import cats.effect.* +import cats.Show +import cats.effect.std.Console +import java.nio.charset.Charset + +class ErrorOutConsole extends Console[IO] { + override def readLineWithCharset(charset: Charset): IO[String] = IO.raiseError(sys.error("Not implemented")) + + override def print[A](a: A)(implicit S: Show[A]): IO[Unit] = IO.consoleForIO.error(a) + + override def println[A](a: A)(implicit S: Show[A]): IO[Unit] = IO.consoleForIO.errorln(a) + + override def error[A](a: A)(implicit S: Show[A]): IO[Unit] = IO.consoleForIO.error(a) + + override def errorln[A](a: A)(implicit S: Show[A]): IO[Unit] = IO.consoleForIO.errorln(a) +} diff --git a/sls/src/org/scala/abusers/sls/ServerImpl.scala b/sls/src/org/scala/abusers/sls/ServerImpl.scala index bc0d6a0..da65783 100644 --- a/sls/src/org/scala/abusers/sls/ServerImpl.scala +++ b/sls/src/org/scala/abusers/sls/ServerImpl.scala @@ -17,6 +17,9 @@ import org.scala.abusers.pc.IOCancelTokens import org.scala.abusers.pc.PresentationCompilerDTOInterop.* import org.scala.abusers.pc.PresentationCompilerProvider import org.scala.abusers.pc.ScalaVersion +import org.scala.abusers.profiling.runtime.ProfilingOps.* +import org.typelevel.otel4s.metrics.Meter +import org.typelevel.otel4s.trace.Tracer import smithy4s.schema.Schema import util.chaining.* @@ -44,7 +47,8 @@ class ServerImpl( computationQueue: ComputationQueue, textDocumentSyncManager: TextDocumentSyncManager, bspStateManager: BspStateManager, -) extends SlsLanguageServer[IO] { +)(using Tracer[IO], Meter[IO]) + extends SlsLanguageServer[IO] { /* There can only be one client for one language-server */ @@ -78,19 +82,27 @@ class ServerImpl( )).guaranteeCase(s => lspClient.logMessage(s"closing initalize with $s")) } - def initialized(params: lsp.InitializedParams): IO[Unit] = computationQueue.synchronously { - bspStateManager.importBuild - } - - def textDocumentCompletionOp(params: lsp.CompletionParams): IO[lsp.TextDocumentCompletionOpOutput] = handleCompletion(params) - def textDocumentDefinitionOp(params: lsp.DefinitionParams): IO[lsp.TextDocumentDefinitionOpOutput] = handleDefinition(params) - def textDocumentDidChange(params: lsp.DidChangeTextDocumentParams): IO[Unit] = handleDidChange(params) - def textDocumentDidClose(params: lsp.DidCloseTextDocumentParams): IO[Unit] = handleDidClose(params) - def textDocumentDidOpen(params: lsp.DidOpenTextDocumentParams): IO[Unit] = handleDidOpen(params) - def textDocumentDidSave(params: lsp.DidSaveTextDocumentParams): IO[Unit] = handleDidSave(params) - def textDocumentHoverOp(params: lsp.HoverParams): IO[lsp.TextDocumentHoverOpOutput] = handleHover(params) - def textDocumentInlayHintOp(params: lsp.InlayHintParams): IO[lsp.TextDocumentInlayHintOpOutput] = handleInlayHints(params) - def textDocumentSignatureHelpOp(params: lsp.SignatureHelpParams): IO[lsp.TextDocumentSignatureHelpOpOutput] = handleSignatureHelp(params) + def initialized(params: lsp.InitializedParams): IO[Unit] = + computationQueue.synchronously(bspStateManager.importBuild) + + def textDocumentCompletionOp(params: lsp.CompletionParams): IO[lsp.TextDocumentCompletionOpOutput] = + Tracer[IO].span("completion").profilingSurround(handleCompletion(params)) + def textDocumentDefinitionOp(params: lsp.DefinitionParams): IO[lsp.TextDocumentDefinitionOpOutput] = + Tracer[IO].span("go-to-defintion").profilingSurround(handleDefinition(params)) + def textDocumentDidChange(params: lsp.DidChangeTextDocumentParams): IO[Unit] = + Tracer[IO].span("did-change").profilingSurround(handleDidChange(params)) + def textDocumentDidClose(params: lsp.DidCloseTextDocumentParams): IO[Unit] = + Tracer[IO].span("did-close").profilingSurround(handleDidClose(params)) + def textDocumentDidOpen(params: lsp.DidOpenTextDocumentParams): IO[Unit] = + Tracer[IO].span("did-open").profilingSurround(handleDidOpen(params)) + def textDocumentDidSave(params: lsp.DidSaveTextDocumentParams): IO[Unit] = + Tracer[IO].span("did-save").profilingSurround(handleDidSave(params)) + def textDocumentHoverOp(params: lsp.HoverParams): IO[lsp.TextDocumentHoverOpOutput] = + Tracer[IO].span("hover").profilingSurround(handleHover(params)) + def textDocumentInlayHintOp(params: lsp.InlayHintParams): IO[lsp.TextDocumentInlayHintOpOutput] = + Tracer[IO].span("inlay-hints").profilingSurround(handleInlayHints(params)) + def textDocumentSignatureHelpOp(params: lsp.SignatureHelpParams): IO[lsp.TextDocumentSignatureHelpOpOutput] = + Tracer[IO].span("signature-help").profilingSurround(handleSignatureHelp(params)) // // TODO: goto type definition with container types def handleCompletion(params: lsp.CompletionParams) = @@ -196,16 +208,21 @@ class ServerImpl( } def handleDidSave(params: lsp.DidSaveTextDocumentParams) = - computationQueue.synchronously { - for { - _ <- textDocumentSyncManager.didSave(params) - info <- bspStateManager.get(URI(params.textDocument.uri)) - } yield info - }.flatMap { info => - bspStateManager.bspServer.generic.buildTargetCompile(bsp.CompileParams(targets = List(info.buildTarget.id))) // we need to handle the case: - // User saves, compilation starts, we don't want to block it, completion starts, during completion compilation ends new classfiles emmited. We need to know which classfiles are new. - // I hardly believe that we should use straight to jar compilation for that - }.void + computationQueue + .synchronously { + for { + _ <- textDocumentSyncManager.didSave(params) + info <- bspStateManager.get(URI(params.textDocument.uri)) + } yield info + } + .flatMap { info => + bspStateManager.bspServer.generic.buildTargetCompile( + bsp.CompileParams(targets = List(info.buildTarget.id)) + ) // we need to handle the case: + // User saves, compilation starts, we don't want to block it, completion starts, during completion compilation ends new classfiles emmited. We need to know which classfiles are new. + // I hardly believe that we should use straight to jar compilation for that + } + .void def handleDidOpen(params: lsp.DidOpenTextDocumentParams) = computationQueue.synchronously { textDocumentSyncManager.didOpen(params) *> bspStateManager.didOpen(lspClient, params) @@ -226,7 +243,7 @@ class ServerImpl( def isSupported(info: ScalaBuildTargetInformation): Boolean = { import scala.math.Ordered.orderingToOrdered - info.scalaVersion > ScalaVersion("3.7.2") + info.scalaVersion > ScalaVersion("3.7.9") } /** We want to debounce compiler diagnostics as they are expensive to compute and we can't really cancel them as @@ -247,21 +264,24 @@ class ServerImpl( .withFieldRenamed(_.everyItem.getMessage, _.everyItem.message) .enableOptionDefaultsToNone .transform - _ <- diagnosticManager.didChange(lspClient, uri.toString, lspDiags) + _ <- diagnosticManager.didChange(lspClient, uri.toString, lspDiags) } yield () } } - params => computationQueue.synchronously { - for { - _ <- textDocumentSyncManager.didChange(params) - _ <- lspClient.logDebug("Updated DocumentState") - uri = URI(params.textDocument.uri) - info <- bspStateManager.get(uri) - } yield (uri, info) - }.flatMap { (uri, info) => - if isSupported(info) then debounce.debounce(pcDiagnostics(info, uri)) else IO.unit - } + params => + computationQueue + .synchronously { + for { + _ <- textDocumentSyncManager.didChange(params) + _ <- lspClient.logDebug("Updated DocumentState") + uri = URI(params.textDocument.uri) + info <- bspStateManager.get(uri) + } yield (uri, info) + } + .flatMap { (uri, info) => + if isSupported(info) then debounce.debounce(pcDiagnostics(info, uri)) else IO.unit + } } private def serverCapabilities: lsp.ServerCapabilities = diff --git a/sls/src/org/scala/abusers/sls/SimpleLanguageServer.scala b/sls/src/org/scala/abusers/sls/SimpleLanguageServer.scala index c56a486..be1003b 100644 --- a/sls/src/org/scala/abusers/sls/SimpleLanguageServer.scala +++ b/sls/src/org/scala/abusers/sls/SimpleLanguageServer.scala @@ -7,6 +7,10 @@ import jsonrpclib.smithy4sinterop.ClientStub import jsonrpclib.CallId import org.scala.abusers.pc.IOCancelTokens import org.scala.abusers.pc.PresentationCompilerProvider +import org.scala.abusers.profiling.runtime.ProfilingIOApp +import org.typelevel.otel4s.metrics.Meter +import org.typelevel.otel4s.trace.Tracer +import cats.effect.std.Console case class BuildServer( generic: bsp.BuildServer[IO], @@ -24,17 +28,30 @@ object BuildServer { ) } -object SimpleScalaServer extends IOApp.Simple { +private case class LSPCancelRequest(id: CallId) + +object LSPCancelRequest { + import io.circe.Codec + given Codec[LSPCancelRequest] = Codec.derived[LSPCancelRequest] + + val cancelTemplate: CancelTemplate = CancelTemplate + .make[LSPCancelRequest]( + "$/cancelRequest", + _.id, + LSPCancelRequest(_), + ) +} + +object SimpleScalaServer extends ProfilingIOApp { import jsonrpclib.smithy4sinterop.ServerEndpoints - val cancelEndpoint = CancelTemplate.make[CallId]("$/cancel", identity, identity) + override def applicationName: String = "simple-language-server" - def run: IO[Unit] = - runResource.useForever + override given console: Console[IO] = ErrorOutConsole() - private def runResource = + override def program(using meter: Meter[IO], tracer: Tracer[IO]) = for { - fs2Channel <- FS2Channel.resource[IO](cancelTemplate = cancelEndpoint.some) + fs2Channel <- FS2Channel.resource[IO](cancelTemplate = LSPCancelRequest.cancelTemplate.some) client <- ClientStub(SlsLanguageClient, fs2Channel).liftTo[IO].toResource serverImpl <- server(client) serverEndpoints <- ServerEndpoints(serverImpl).liftTo[IO].toResource @@ -56,10 +73,10 @@ object SimpleScalaServer extends IOApp.Simple { ) .compile .drain - .background + .toResource } yield () - private def server(lspClient: SlsLanguageClient[IO]): Resource[IO, ServerImpl] = + private def server(lspClient: SlsLanguageClient[IO])(using Tracer[IO], Meter[IO]): Resource[IO, ServerImpl] = for { steward <- ResourceSupervisor[IO] pcProvider <- PresentationCompilerProvider.instance.toResource @@ -69,5 +86,15 @@ object SimpleScalaServer extends IOApp.Simple { cancelTokens <- IOCancelTokens.instance diagnosticManager <- DiagnosticManager.instance.toResource computationQueue <- ComputationQueue.instance.toResource - } yield ServerImpl(pcProvider, cancelTokens, diagnosticManager, steward, bspClientDeferred, lspClient, computationQueue, textDocumentSync, bspStateManager) + } yield ServerImpl( + pcProvider, + cancelTokens, + diagnosticManager, + steward, + bspClientDeferred, + lspClient, + computationQueue, + textDocumentSync, + bspStateManager, + ) } diff --git a/sls/src/org/scala/abusers/sls/pc/PresentationCompilerProvider.scala b/sls/src/org/scala/abusers/sls/pc/PresentationCompilerProvider.scala index 3be198c..3df71b9 100644 --- a/sls/src/org/scala/abusers/sls/pc/PresentationCompilerProvider.scala +++ b/sls/src/org/scala/abusers/sls/pc/PresentationCompilerProvider.scala @@ -7,13 +7,13 @@ import com.evolution.scache.ExpiringCache import coursierapi.* import org.scala.abusers.sls.ScalaBuildTargetInformation import org.scala.abusers.sls.ScalaBuildTargetInformation.* +import org.scala.abusers.sls.SynchronizedState import os.Path import java.net.URLClassLoader import scala.concurrent.duration.* import scala.jdk.CollectionConverters.* import scala.meta.pc.PresentationCompiler -import org.scala.abusers.sls.SynchronizedState class PresentationCompilerProvider( serviceLoader: BlockingServiceLoader, diff --git a/sls/test/src/org/scala/abusers/sls/DocumentSyncTests.scala b/sls/test/src/org/scala/abusers/sls/DocumentSyncTests.scala index 447b9ed..c3dc0eb 100644 --- a/sls/test/src/org/scala/abusers/sls/DocumentSyncTests.scala +++ b/sls/test/src/org/scala/abusers/sls/DocumentSyncTests.scala @@ -1,14 +1,14 @@ package org.scala.abusers.sls +import cats.effect.IO import lsp.* import weaver.SimpleIOSuite -import cats.effect.IO object TextDocumentSyncSuite extends SimpleIOSuite { class TestComputationQueue extends ComputationQueue { override def synchronously[A](computation: (SynchronizedState) ?=> IO[A]): IO[A] = computation - def unsafeGetState: SynchronizedState = summon[SynchronizedState] + def unsafeGetState: SynchronizedState = summon[SynchronizedState] } given SynchronizedState = TestComputationQueue().unsafeGetState