FEATURE:: Support for metrics collection - Prometheus and Open Telemetry (#3420)
* adding support for prometheus and grafana * open telemetry * lint fixes * missing counter and telemetry standardization --------- Co-authored-by: Henry <hzj94@hotmail.com>
This commit is contained in:
parent
8466e1a0b0
commit
fe03683f0c
|
|
@ -53,6 +53,19 @@ BLOB_STORAGE_PATH=/root/.flowise/storage
|
||||||
# APIKEY_STORAGE_TYPE=json (json | db)
|
# APIKEY_STORAGE_TYPE=json (json | db)
|
||||||
# SHOW_COMMUNITY_NODES=true
|
# SHOW_COMMUNITY_NODES=true
|
||||||
|
|
||||||
|
######################
|
||||||
|
# METRICS COLLECTION
|
||||||
|
#######################
|
||||||
|
# ENABLE_METRICS=false
|
||||||
|
# METRICS_PROVIDER=prometheus # prometheus | open_telemetry
|
||||||
|
# METRICS_INCLUDE_NODE_METRICS=true # default is true
|
||||||
|
# METRICS_SERVICE_NAME=FlowiseAI
|
||||||
|
|
||||||
|
# ONLY NEEDED if METRICS_PROVIDER=open_telemetry
|
||||||
|
# METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT=http://localhost:4318/v1/metrics
|
||||||
|
# METRICS_OPEN_TELEMETRY_PROTOCOL=http # http | grpc | proto (default is http)
|
||||||
|
# METRICS_OPEN_TELEMETRY_DEBUG=true # default is false
|
||||||
|
|
||||||
# Uncomment the following lines to enable global agent proxy
|
# Uncomment the following lines to enable global agent proxy
|
||||||
# see https://www.npmjs.com/package/global-agent for more details
|
# see https://www.npmjs.com/package/global-agent for more details
|
||||||
# GLOBAL_AGENT_HTTP_PROXY=CorporateHttpProxyUrl
|
# GLOBAL_AGENT_HTTP_PROXY=CorporateHttpProxyUrl
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,639 @@
|
||||||
|
{
|
||||||
|
"annotations": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"builtIn": 1,
|
||||||
|
"datasource": {
|
||||||
|
"type": "grafana",
|
||||||
|
"uid": "-- Grafana --"
|
||||||
|
},
|
||||||
|
"enable": true,
|
||||||
|
"hide": true,
|
||||||
|
"iconColor": "rgba(0, 211, 255, 1)",
|
||||||
|
"name": "Annotations & Alerts",
|
||||||
|
"type": "dashboard"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"enable": true,
|
||||||
|
"expr": "ALERTS",
|
||||||
|
"hide": false,
|
||||||
|
"iconColor": "rgba(255, 96, 96, 1)",
|
||||||
|
"limit": 100,
|
||||||
|
"name": "Alerts",
|
||||||
|
"showIn": 0,
|
||||||
|
"step": "10s",
|
||||||
|
"type": "alert"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": "Application metrics",
|
||||||
|
"editable": true,
|
||||||
|
"fiscalYearStartMonth": 0,
|
||||||
|
"graphTooltip": 0,
|
||||||
|
"id": 3,
|
||||||
|
"links": [],
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisBorderShow": false,
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"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": "auto",
|
||||||
|
"spanNulls": false,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 11,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"disableTextWrap": false,
|
||||||
|
"editorMode": "code",
|
||||||
|
"expr": "sum(rate(internal_predictions[1m])) by (status) * 60",
|
||||||
|
"fullMetaSearch": false,
|
||||||
|
"hide": false,
|
||||||
|
"includeNullMetadata": false,
|
||||||
|
"instant": false,
|
||||||
|
"legendFormat": "__auto",
|
||||||
|
"range": true,
|
||||||
|
"refId": "B",
|
||||||
|
"useBackend": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Internal Predictions",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsed": false,
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 1,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 8
|
||||||
|
},
|
||||||
|
"id": 7,
|
||||||
|
"panels": [],
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Throughput",
|
||||||
|
"type": "row"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"match": "null",
|
||||||
|
"result": {
|
||||||
|
"text": "N/A"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "special"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"max": 1,
|
||||||
|
"min": 0,
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "rgba(50, 172, 45, 0.97)",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "rgba(237, 129, 40, 0.89)",
|
||||||
|
"value": 0.1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "rgba(245, 54, 54, 0.9)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "none"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 7,
|
||||||
|
"w": 6,
|
||||||
|
"x": 0,
|
||||||
|
"y": 9
|
||||||
|
},
|
||||||
|
"hideTimeOverride": false,
|
||||||
|
"id": 6,
|
||||||
|
"maxDataPoints": 100,
|
||||||
|
"options": {
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "none",
|
||||||
|
"justifyMode": "auto",
|
||||||
|
"orientation": "horizontal",
|
||||||
|
"percentChangeColorMode": "standard",
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"mean"
|
||||||
|
],
|
||||||
|
"fields": "/^Value$/",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"showPercentChange": false,
|
||||||
|
"textMode": "auto",
|
||||||
|
"wideLayout": true
|
||||||
|
},
|
||||||
|
"pluginVersion": "11.1.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"expr": "sum(increase(http_request_duration_ms_count{code=~\"^5..$\"}[1m])) / sum(increase(http_request_duration_ms_count[1m]))",
|
||||||
|
"format": "time_series",
|
||||||
|
"interval": "",
|
||||||
|
"intervalFactor": 2,
|
||||||
|
"legendFormat": "",
|
||||||
|
"refId": "A",
|
||||||
|
"step": 20
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Error rate",
|
||||||
|
"type": "stat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisBorderShow": false,
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"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": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "rpm"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 7,
|
||||||
|
"w": 18,
|
||||||
|
"x": 6,
|
||||||
|
"y": 9
|
||||||
|
},
|
||||||
|
"id": 1,
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"url": "/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "multi",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"expr": "sum(rate(http_request_duration_ms_count[1m])) by (service, route, method, code) * 60",
|
||||||
|
"format": "time_series",
|
||||||
|
"hide": false,
|
||||||
|
"intervalFactor": 2,
|
||||||
|
"legendFormat": "{{service}} - {{method}} {{route}} {{code}}",
|
||||||
|
"metric": "",
|
||||||
|
"refId": "A",
|
||||||
|
"step": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Throughput",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsed": true,
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 1,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 16
|
||||||
|
},
|
||||||
|
"id": 8,
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisBorderShow": false,
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"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": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "ms"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 7,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 17
|
||||||
|
},
|
||||||
|
"id": 4,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "multi",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"expr": "histogram_quantile(0.5, sum(rate(http_request_duration_ms_bucket[1m])) by (le, service, route, method))",
|
||||||
|
"format": "time_series",
|
||||||
|
"intervalFactor": 2,
|
||||||
|
"legendFormat": "{{service}} - {{method}} {{route}}",
|
||||||
|
"refId": "A",
|
||||||
|
"step": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Median Response Time",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisBorderShow": false,
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"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": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "ms"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 7,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 24
|
||||||
|
},
|
||||||
|
"id": 2,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "multi",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"expr": "histogram_quantile(0.95, sum(rate(http_request_duration_ms_bucket[1m])) by (le, service, route, method))",
|
||||||
|
"format": "time_series",
|
||||||
|
"interval": "",
|
||||||
|
"intervalFactor": 2,
|
||||||
|
"legendFormat": "{{service}} - {{method}} {{route}}",
|
||||||
|
"refId": "A",
|
||||||
|
"step": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "95th Response Time",
|
||||||
|
"type": "timeseries"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Response time",
|
||||||
|
"type": "row"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsed": false,
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 1,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 17
|
||||||
|
},
|
||||||
|
"id": 10,
|
||||||
|
"panels": [],
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "cds4j1ybfuhogb"
|
||||||
|
},
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Business",
|
||||||
|
"type": "row"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"refresh": "10s",
|
||||||
|
"schemaVersion": 39,
|
||||||
|
"tags": [],
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"from": "now-15m",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"timepicker": {
|
||||||
|
"refresh_intervals": [
|
||||||
|
"5s",
|
||||||
|
"10s",
|
||||||
|
"30s",
|
||||||
|
"1m",
|
||||||
|
"5m",
|
||||||
|
"15m",
|
||||||
|
"30m",
|
||||||
|
"1h",
|
||||||
|
"2h",
|
||||||
|
"1d"
|
||||||
|
],
|
||||||
|
"time_options": [
|
||||||
|
"5m",
|
||||||
|
"15m",
|
||||||
|
"1h",
|
||||||
|
"6h",
|
||||||
|
"12h",
|
||||||
|
"24h",
|
||||||
|
"2d",
|
||||||
|
"7d",
|
||||||
|
"30d"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"timezone": "browser",
|
||||||
|
"title": "FlowiseAI - Custom Metrics",
|
||||||
|
"uid": "dds4pojnfec5cc",
|
||||||
|
"version": 8,
|
||||||
|
"weekStart": ""
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,15 @@
|
||||||
|
version: "2"
|
||||||
|
services:
|
||||||
|
otel-collector:
|
||||||
|
image: otel/opentelemetry-collector-contrib
|
||||||
|
command: ["--config=/etc/otelcol-contrib/config.yaml", "--feature-gates=-exporter.datadogexporter.DisableAPMStats", "${OTELCOL_ARGS}"]
|
||||||
|
volumes:
|
||||||
|
- ./otel.config.yml:/etc/otelcol-contrib/config.yaml
|
||||||
|
ports:
|
||||||
|
- 1888:1888 # pprof extension
|
||||||
|
- 8888:8888 # Prometheus metrics exposed by the Collector
|
||||||
|
- 8889:8889 # Prometheus exporter metrics
|
||||||
|
- 13133:13133 # health_check extension
|
||||||
|
- 4317:4317 # OTLP gRPC receiver
|
||||||
|
- 4318:4318 # OTLP http receiver
|
||||||
|
- 55679:55679 # zpages extension
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
receivers:
|
||||||
|
otlp:
|
||||||
|
protocols:
|
||||||
|
http:
|
||||||
|
endpoint: 0.0.0.0:4318
|
||||||
|
grpc:
|
||||||
|
endpoint: 0.0.0.0:4317
|
||||||
|
# The hostmetrics receiver is required to get correct infrastructure metrics in Datadog.
|
||||||
|
hostmetrics:
|
||||||
|
collection_interval: 10s
|
||||||
|
scrapers:
|
||||||
|
paging:
|
||||||
|
metrics:
|
||||||
|
system.paging.utilization:
|
||||||
|
enabled: true
|
||||||
|
cpu:
|
||||||
|
metrics:
|
||||||
|
system.cpu.utilization:
|
||||||
|
enabled: true
|
||||||
|
disk:
|
||||||
|
filesystem:
|
||||||
|
metrics:
|
||||||
|
system.filesystem.utilization:
|
||||||
|
enabled: true
|
||||||
|
load:
|
||||||
|
memory:
|
||||||
|
network:
|
||||||
|
|
||||||
|
# The prometheus receiver scrapes metrics needed for the OpenTelemetry Collector Dashboard.
|
||||||
|
prometheus:
|
||||||
|
config:
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: 'otelcol'
|
||||||
|
scrape_interval: 10s
|
||||||
|
static_configs:
|
||||||
|
- targets: ['0.0.0.0:8888']
|
||||||
|
|
||||||
|
filelog:
|
||||||
|
include_file_path: true
|
||||||
|
poll_interval: 10s
|
||||||
|
include:
|
||||||
|
- /var/log/**/*example*/*.log
|
||||||
|
|
||||||
|
processors:
|
||||||
|
batch:
|
||||||
|
send_batch_max_size: 100
|
||||||
|
send_batch_size: 10
|
||||||
|
timeout: 10s
|
||||||
|
|
||||||
|
connectors:
|
||||||
|
datadog/connector:
|
||||||
|
|
||||||
|
exporters:
|
||||||
|
datadog/exporter:
|
||||||
|
api:
|
||||||
|
site: us5.datadoghq.com
|
||||||
|
key: "4f5778c6cf5381df89606004b4cacbc9"
|
||||||
|
|
||||||
|
service:
|
||||||
|
pipelines:
|
||||||
|
metrics:
|
||||||
|
receivers: [datadog/connector, hostmetrics, prometheus, otlp]
|
||||||
|
processors: [batch]
|
||||||
|
exporters: [datadog/exporter]
|
||||||
|
traces:
|
||||||
|
receivers: [otlp]
|
||||||
|
processors: [batch]
|
||||||
|
exporters: [datadog/connector, datadog/exporter]
|
||||||
|
logs:
|
||||||
|
receivers: [otlp, filelog]
|
||||||
|
processors: [batch]
|
||||||
|
exporters: [datadog/exporter]
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
global:
|
||||||
|
scrape_interval: 5s
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: "FlowiseAI"
|
||||||
|
static_configs:
|
||||||
|
- targets: ["localhost:8080","localhost:3000"]
|
||||||
|
|
||||||
|
metrics_path: /api/v1/metrics/
|
||||||
|
scheme: http
|
||||||
|
|
@ -4,14 +4,14 @@ Postgres Record Manager integration for Flowise
|
||||||
|
|
||||||
## 🌱 Env Variables
|
## 🌱 Env Variables
|
||||||
|
|
||||||
| Variable | Description | Type | Default |
|
| Variable | Description | Type | Default |
|
||||||
| ---------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------- |
|
| --------------------------------- | ----------------------------------------------- | ------ | ----------------- |
|
||||||
| POSTGRES_RECORDMANAGER_HOST | Default `host` for Postgres Record Manager | String | |
|
| POSTGRES_RECORDMANAGER_HOST | Default `host` for Postgres Record Manager | String | |
|
||||||
| POSTGRES_RECORDMANAGER_PORT | Default `port` for Postgres Record Manager | Number | 5432 |
|
| POSTGRES_RECORDMANAGER_PORT | Default `port` for Postgres Record Manager | Number | 5432 |
|
||||||
| POSTGRES_RECORDMANAGER_USER | Default `user` for Postgres Record Manager | String | |
|
| POSTGRES_RECORDMANAGER_USER | Default `user` for Postgres Record Manager | String | |
|
||||||
| POSTGRES_RECORDMANAGER_PASSWORD | Default `password` for Postgres Record Manager | String | |
|
| POSTGRES_RECORDMANAGER_PASSWORD | Default `password` for Postgres Record Manager | String | |
|
||||||
| POSTGRES_RECORDMANAGER_DATABASE | Default `database` for Postgres Record Manager | String | |
|
| POSTGRES_RECORDMANAGER_DATABASE | Default `database` for Postgres Record Manager | String | |
|
||||||
| POSTGRES_RECORDMANAGER_TABLE_NAME | Default `tableName` for Postgres Record Manager | String | upsertion_records |
|
| POSTGRES_RECORDMANAGER_TABLE_NAME | Default `tableName` for Postgres Record Manager | String | upsertion_records |
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,15 @@ Postgres Vector Store integration for Flowise
|
||||||
|
|
||||||
## 🌱 Env Variables
|
## 🌱 Env Variables
|
||||||
|
|
||||||
| Variable | Description | Type | Default |
|
| Variable | Description | Type | Default |
|
||||||
| ---------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------- |
|
| ---------------------------------------- | ----------------------------------------------------- | ------ | ----------- |
|
||||||
| POSTGRES_VECTORSTORE_HOST | Default `host` for Postgres Vector Store | String | |
|
| POSTGRES_VECTORSTORE_HOST | Default `host` for Postgres Vector Store | String | |
|
||||||
| POSTGRES_VECTORSTORE_PORT | Default `port` for Postgres Vector Store | Number | 5432 |
|
| POSTGRES_VECTORSTORE_PORT | Default `port` for Postgres Vector Store | Number | 5432 |
|
||||||
| POSTGRES_VECTORSTORE_USER | Default `user` for Postgres Vector Store | String | |
|
| POSTGRES_VECTORSTORE_USER | Default `user` for Postgres Vector Store | String | |
|
||||||
| POSTGRES_VECTORSTORE_PASSWORD | Default `password` for Postgres Vector Store | String | |
|
| POSTGRES_VECTORSTORE_PASSWORD | Default `password` for Postgres Vector Store | String | |
|
||||||
| POSTGRES_VECTORSTORE_DATABASE | Default `database` for Postgres Vector Store | String | |
|
| POSTGRES_VECTORSTORE_DATABASE | Default `database` for Postgres Vector Store | String | |
|
||||||
| POSTGRES_VECTORSTORE_TABLE_NAME | Default `tableName` for Postgres Vector Store | String | documents |
|
| POSTGRES_VECTORSTORE_TABLE_NAME | Default `tableName` for Postgres Vector Store | String | documents |
|
||||||
| POSTGRES_VECTORSTORE_CONTENT_COLUMN_NAME | Default `contentColumnName` for Postgres Vector Store | String | pageContent |
|
| POSTGRES_VECTORSTORE_CONTENT_COLUMN_NAME | Default `contentColumnName` for Postgres Vector Store | String | pageContent |
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,19 @@ PORT=3000
|
||||||
# APIKEY_STORAGE_TYPE=json (json | db)
|
# APIKEY_STORAGE_TYPE=json (json | db)
|
||||||
# SHOW_COMMUNITY_NODES=true
|
# SHOW_COMMUNITY_NODES=true
|
||||||
|
|
||||||
|
######################
|
||||||
|
# METRICS COLLECTION
|
||||||
|
#######################
|
||||||
|
# ENABLE_METRICS=false
|
||||||
|
# METRICS_PROVIDER=prometheus # prometheus | open_telemetry
|
||||||
|
# METRICS_INCLUDE_NODE_METRICS=true # default is true
|
||||||
|
# METRICS_SERVICE_NAME=FlowiseAI
|
||||||
|
|
||||||
|
# ONLY NEEDED if METRICS_PROVIDER=open_telemetry
|
||||||
|
# METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT=http://localhost:4318/v1/metrics
|
||||||
|
# METRICS_OPEN_TELEMETRY_PROTOCOL=http # http | grpc | proto (default is http)
|
||||||
|
# METRICS_OPEN_TELEMETRY_DEBUG=true # default is false
|
||||||
|
|
||||||
# Uncomment the following lines to enable global agent proxy
|
# Uncomment the following lines to enable global agent proxy
|
||||||
# see https://www.npmjs.com/package/global-agent for more details
|
# see https://www.npmjs.com/package/global-agent for more details
|
||||||
# GLOBAL_AGENT_HTTP_PROXY=CorporateHttpProxyUrl
|
# GLOBAL_AGENT_HTTP_PROXY=CorporateHttpProxyUrl
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,20 @@
|
||||||
"license": "SEE LICENSE IN LICENSE.md",
|
"license": "SEE LICENSE IN LICENSE.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oclif/core": "^1.13.10",
|
"@oclif/core": "^1.13.10",
|
||||||
|
"@opentelemetry/api": "^1.3.0",
|
||||||
|
"@opentelemetry/core": "1.27.0",
|
||||||
|
"@opentelemetry/exporter-metrics-otlp-grpc": "0.54.0",
|
||||||
|
"@opentelemetry/exporter-metrics-otlp-http": "0.54.0",
|
||||||
|
"@opentelemetry/exporter-metrics-otlp-proto": "0.54.0",
|
||||||
|
"@opentelemetry/exporter-trace-otlp-grpc": "0.54.0",
|
||||||
|
"@opentelemetry/exporter-trace-otlp-http": "0.54.0",
|
||||||
|
"@opentelemetry/exporter-trace-otlp-proto": "0.54.0",
|
||||||
|
"@opentelemetry/resources": "1.27.0",
|
||||||
|
"@opentelemetry/sdk-metrics": "1.27.0",
|
||||||
|
"@opentelemetry/sdk-trace-base": "1.27.0",
|
||||||
|
"@opentelemetry/semantic-conventions": "1.27.0",
|
||||||
|
"@opentelemetry/auto-instrumentations-node": "^0.52.0",
|
||||||
|
"@opentelemetry/sdk-node": "^0.54.0",
|
||||||
"@types/lodash": "^4.14.202",
|
"@types/lodash": "^4.14.202",
|
||||||
"@types/uuid": "^9.0.7",
|
"@types/uuid": "^9.0.7",
|
||||||
"async-mutex": "^0.4.0",
|
"async-mutex": "^0.4.0",
|
||||||
|
|
@ -79,6 +93,7 @@
|
||||||
"openai": "^4.57.3",
|
"openai": "^4.57.3",
|
||||||
"pg": "^8.11.1",
|
"pg": "^8.11.1",
|
||||||
"posthog-node": "^3.5.0",
|
"posthog-node": "^3.5.0",
|
||||||
|
"prom-client": "^15.1.3",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"sanitize-html": "^2.11.0",
|
"sanitize-html": "^2.11.0",
|
||||||
"socket.io": "^4.6.1",
|
"socket.io": "^4.6.1",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
export interface IMetricsProvider {
|
||||||
|
getName(): string
|
||||||
|
initializeCounters(): void
|
||||||
|
setupMetricsEndpoint(): void
|
||||||
|
incrementCounter(counter: FLOWISE_METRIC_COUNTERS, payload: any): void
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum FLOWISE_COUNTER_STATUS {
|
||||||
|
SUCCESS = 'success',
|
||||||
|
FAILURE = 'failure'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum FLOWISE_METRIC_COUNTERS {
|
||||||
|
CHATFLOW_CREATED = 'chatflow_created',
|
||||||
|
AGENTFLOW_CREATED = 'agentflow_created',
|
||||||
|
ASSISTANT_CREATED = 'assistant_created',
|
||||||
|
TOOL_CREATED = 'tool_created',
|
||||||
|
VECTORSTORE_UPSERT = 'vector_upserted',
|
||||||
|
|
||||||
|
CHATFLOW_PREDICTION_INTERNAL = 'chatflow_prediction_internal',
|
||||||
|
CHATFLOW_PREDICTION_EXTERNAL = 'chatflow_prediction_external',
|
||||||
|
|
||||||
|
AGENTFLOW_PREDICTION_INTERNAL = 'agentflow_prediction_internal',
|
||||||
|
AGENTFLOW_PREDICTION_EXTERNAL = 'agentflow_prediction_external'
|
||||||
|
}
|
||||||
|
|
@ -22,6 +22,9 @@ import flowiseApiV1Router from './routes'
|
||||||
import errorHandlerMiddleware from './middlewares/errors'
|
import errorHandlerMiddleware from './middlewares/errors'
|
||||||
import { SSEStreamer } from './utils/SSEStreamer'
|
import { SSEStreamer } from './utils/SSEStreamer'
|
||||||
import { validateAPIKey } from './utils/validateKey'
|
import { validateAPIKey } from './utils/validateKey'
|
||||||
|
import { IMetricsProvider } from './Interface.Metrics'
|
||||||
|
import { Prometheus } from './metrics/Prometheus'
|
||||||
|
import { OpenTelemetry } from './metrics/OpenTelemetry'
|
||||||
import 'global-agent/bootstrap'
|
import 'global-agent/bootstrap'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|
@ -40,6 +43,7 @@ export class App {
|
||||||
telemetry: Telemetry
|
telemetry: Telemetry
|
||||||
AppDataSource: DataSource = getDataSource()
|
AppDataSource: DataSource = getDataSource()
|
||||||
sseStreamer: SSEStreamer
|
sseStreamer: SSEStreamer
|
||||||
|
metricsProvider: IMetricsProvider
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.app = express()
|
this.app = express()
|
||||||
|
|
@ -138,7 +142,8 @@ export class App {
|
||||||
'/api/v1/ip',
|
'/api/v1/ip',
|
||||||
'/api/v1/ping',
|
'/api/v1/ping',
|
||||||
'/api/v1/version',
|
'/api/v1/version',
|
||||||
'/api/v1/attachments'
|
'/api/v1/attachments',
|
||||||
|
'/api/v1/metrics'
|
||||||
]
|
]
|
||||||
const URL_CASE_INSENSITIVE_REGEX: RegExp = /\/api\/v1\//i
|
const URL_CASE_INSENSITIVE_REGEX: RegExp = /\/api\/v1\//i
|
||||||
const URL_CASE_SENSITIVE_REGEX: RegExp = /\/api\/v1\//
|
const URL_CASE_SENSITIVE_REGEX: RegExp = /\/api\/v1\//
|
||||||
|
|
@ -204,6 +209,28 @@ export class App {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.env.ENABLE_METRICS === 'true') {
|
||||||
|
switch (process.env.METRICS_PROVIDER) {
|
||||||
|
// default to prometheus
|
||||||
|
case 'prometheus':
|
||||||
|
case undefined:
|
||||||
|
this.metricsProvider = new Prometheus(this.app)
|
||||||
|
break
|
||||||
|
case 'open_telemetry':
|
||||||
|
this.metricsProvider = new OpenTelemetry(this.app)
|
||||||
|
break
|
||||||
|
// add more cases for other metrics providers here
|
||||||
|
}
|
||||||
|
if (this.metricsProvider) {
|
||||||
|
await this.metricsProvider.initializeCounters()
|
||||||
|
logger.info(`📊 [server]: Metrics Provider [${this.metricsProvider.getName()}] has been initialized!`)
|
||||||
|
} else {
|
||||||
|
logger.error(
|
||||||
|
"❌ [server]: Metrics collection is enabled, but failed to initialize provider (valid values are 'prometheus' or 'open_telemetry'."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.app.use('/api/v1', flowiseApiV1Router)
|
this.app.use('/api/v1', flowiseApiV1Router)
|
||||||
this.sseStreamer = new SSEStreamer(this.app)
|
this.sseStreamer = new SSEStreamer(this.app)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,157 @@
|
||||||
|
import { FLOWISE_METRIC_COUNTERS, IMetricsProvider } from '../Interface.Metrics'
|
||||||
|
import { Resource } from '@opentelemetry/resources'
|
||||||
|
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions'
|
||||||
|
import { MeterProvider, PeriodicExportingMetricReader, Histogram } from '@opentelemetry/sdk-metrics'
|
||||||
|
import { diag, DiagLogLevel, DiagConsoleLogger, Attributes, Counter } from '@opentelemetry/api'
|
||||||
|
import { getVersion } from 'flowise-components'
|
||||||
|
import express from 'express'
|
||||||
|
|
||||||
|
export class OpenTelemetry implements IMetricsProvider {
|
||||||
|
private app: express.Application
|
||||||
|
private resource: Resource
|
||||||
|
private otlpMetricExporter: any
|
||||||
|
// private otlpTraceExporter: any
|
||||||
|
// private tracerProvider: NodeTracerProvider
|
||||||
|
private metricReader: PeriodicExportingMetricReader
|
||||||
|
private meterProvider: MeterProvider
|
||||||
|
|
||||||
|
// Map to hold all counters and histograms
|
||||||
|
private counters = new Map<string, Counter | Histogram>()
|
||||||
|
private httpRequestCounter: Counter
|
||||||
|
private httpRequestDuration: any
|
||||||
|
|
||||||
|
constructor(app: express.Application) {
|
||||||
|
this.app = app
|
||||||
|
|
||||||
|
if (!process.env.METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT) {
|
||||||
|
throw new Error('METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT is not defined')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.METRICS_OPEN_TELEMETRY_DEBUG === 'true') {
|
||||||
|
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getName(): string {
|
||||||
|
return 'OpenTelemetry'
|
||||||
|
}
|
||||||
|
|
||||||
|
async initializeCounters(): Promise<void> {
|
||||||
|
// Define the resource with the service name for trace grouping
|
||||||
|
const flowiseVersion = await getVersion()
|
||||||
|
|
||||||
|
this.resource = new Resource({
|
||||||
|
[ATTR_SERVICE_NAME]: process.env.METRICS_SERVICE_NAME || 'FlowiseAI',
|
||||||
|
[ATTR_SERVICE_VERSION]: flowiseVersion.version // Version as a label
|
||||||
|
})
|
||||||
|
|
||||||
|
const metricProtocol = process.env.METRICS_OPEN_TELEMETRY_PROTOCOL || 'http' // Default to 'http'
|
||||||
|
// Conditionally import the correct OTLP exporters based on protocol
|
||||||
|
let OTLPMetricExporter
|
||||||
|
if (metricProtocol === 'http') {
|
||||||
|
OTLPMetricExporter = require('@opentelemetry/exporter-metrics-otlp-http').OTLPMetricExporter
|
||||||
|
} else if (metricProtocol === 'grpc') {
|
||||||
|
OTLPMetricExporter = require('@opentelemetry/exporter-metrics-otlp-grpc').OTLPMetricExporter
|
||||||
|
} else if (metricProtocol === 'proto') {
|
||||||
|
OTLPMetricExporter = require('@opentelemetry/exporter-metrics-otlp-proto').OTLPMetricExporter
|
||||||
|
} else {
|
||||||
|
console.error('Invalid METRICS_OPEN_TELEMETRY_PROTOCOL specified. Please set it to "http", "grpc", or "proto".')
|
||||||
|
process.exit(1) // Exit if invalid protocol type is specified
|
||||||
|
}
|
||||||
|
|
||||||
|
this.otlpMetricExporter = new OTLPMetricExporter({
|
||||||
|
url: process.env.METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT // OTLP endpoint for metrics
|
||||||
|
})
|
||||||
|
|
||||||
|
this.metricReader = new PeriodicExportingMetricReader({
|
||||||
|
exporter: this.otlpMetricExporter,
|
||||||
|
exportIntervalMillis: 5000 // Export metrics every 5 seconds
|
||||||
|
})
|
||||||
|
this.meterProvider = new MeterProvider({ resource: this.resource, readers: [this.metricReader] })
|
||||||
|
|
||||||
|
const meter = this.meterProvider.getMeter('flowise-metrics')
|
||||||
|
// look at the FLOWISE_COUNTER enum in Interface.Metrics.ts and get all values
|
||||||
|
// for each counter in the enum, create a new promClient.Counter and add it to the registry
|
||||||
|
const enumEntries = Object.entries(FLOWISE_METRIC_COUNTERS)
|
||||||
|
enumEntries.forEach(([name, value]) => {
|
||||||
|
// derive proper counter name from the enum value (chatflow_created = Chatflow Created)
|
||||||
|
const properCounterName: string = name.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase())
|
||||||
|
this.counters.set(
|
||||||
|
value,
|
||||||
|
meter.createCounter(value, {
|
||||||
|
description: properCounterName
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// in addition to the enum counters, add a few more custom counters
|
||||||
|
|
||||||
|
const versionGuage = meter.createGauge('flowise_version', {
|
||||||
|
description: 'Flowise version'
|
||||||
|
})
|
||||||
|
// remove the last dot from the version string, e.g. 2.1.3 -> 2.13 (guage needs a number - float)
|
||||||
|
const formattedVersion = flowiseVersion.version.replace(/\.(\d+)$/, '$1')
|
||||||
|
versionGuage.record(parseFloat(formattedVersion))
|
||||||
|
|
||||||
|
// Counter for HTTP requests with method, path, and status as labels
|
||||||
|
this.httpRequestCounter = meter.createCounter('http_requests_total', {
|
||||||
|
description: 'Counts the number of HTTP requests received'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Histogram to measure HTTP request duration in milliseconds
|
||||||
|
this.httpRequestDuration = meter.createHistogram('http_request_duration_ms', {
|
||||||
|
description: 'Records the duration of HTTP requests in ms'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to record HTTP request duration
|
||||||
|
private recordHttpRequestDuration(durationMs: number, method: string, path: string, status: number) {
|
||||||
|
this.httpRequestDuration.record(durationMs, {
|
||||||
|
method,
|
||||||
|
path,
|
||||||
|
status: status.toString()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to record HTTP requests with specific labels
|
||||||
|
private recordHttpRequest(method: string, path: string, status: number) {
|
||||||
|
this.httpRequestCounter.add(1, {
|
||||||
|
method,
|
||||||
|
path,
|
||||||
|
status: status.toString()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async setupMetricsEndpoint(): Promise<void> {
|
||||||
|
// Graceful shutdown for telemetry data flushing
|
||||||
|
process.on('SIGTERM', async () => {
|
||||||
|
await this.metricReader.shutdown()
|
||||||
|
await this.meterProvider.shutdown()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Runs before each requests
|
||||||
|
this.app.use((req, res, next) => {
|
||||||
|
res.locals.startEpoch = Date.now()
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Runs after each requests
|
||||||
|
this.app.use((req, res, next) => {
|
||||||
|
res.on('finish', async () => {
|
||||||
|
if (res.locals.startEpoch) {
|
||||||
|
const responseTimeInMs = Date.now() - res.locals.startEpoch
|
||||||
|
this.recordHttpRequest(req.method, req.path, res.statusCode)
|
||||||
|
this.recordHttpRequestDuration(responseTimeInMs, req.method, req.path, res.statusCode)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async incrementCounter(counter: string, payload: any): Promise<void> {
|
||||||
|
// Increment OpenTelemetry counter with the payload
|
||||||
|
if (this.counters.has(counter)) {
|
||||||
|
;(this.counters.get(counter) as Counter<Attributes>).add(1, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
import { FLOWISE_METRIC_COUNTERS, IMetricsProvider } from '../Interface.Metrics'
|
||||||
|
import express from 'express'
|
||||||
|
import promClient, { Counter, Histogram, Registry } from 'prom-client'
|
||||||
|
import { getVersion } from 'flowise-components'
|
||||||
|
|
||||||
|
export class Prometheus implements IMetricsProvider {
|
||||||
|
private app: express.Application
|
||||||
|
private readonly register: Registry
|
||||||
|
private counters: Map<string, promClient.Counter<string> | promClient.Gauge<string> | promClient.Histogram<string>>
|
||||||
|
private requestCounter: Counter<string>
|
||||||
|
private httpRequestDurationMicroseconds: Histogram<string>
|
||||||
|
|
||||||
|
constructor(app: express.Application) {
|
||||||
|
this.app = app
|
||||||
|
this.register = new promClient.Registry()
|
||||||
|
}
|
||||||
|
|
||||||
|
public getName(): string {
|
||||||
|
return 'Prometheus'
|
||||||
|
}
|
||||||
|
|
||||||
|
async initializeCounters(): Promise<void> {
|
||||||
|
const serviceName: string = process.env.METRICS_SERVICE_NAME || 'FlowiseAI'
|
||||||
|
this.register.setDefaultLabels({
|
||||||
|
app: serviceName
|
||||||
|
})
|
||||||
|
|
||||||
|
// look at the FLOWISE_COUNTER enum in Interface.Metrics.ts and get all values
|
||||||
|
// for each counter in the enum, create a new promClient.Counter and add it to the registry
|
||||||
|
this.counters = new Map<string, promClient.Counter<string>>()
|
||||||
|
const enumEntries = Object.entries(FLOWISE_METRIC_COUNTERS)
|
||||||
|
enumEntries.forEach(([name, value]) => {
|
||||||
|
// derive proper counter name from the enum value (chatflow_created = Chatflow Created)
|
||||||
|
const properCounterName: string = name.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase())
|
||||||
|
this.counters.set(
|
||||||
|
value,
|
||||||
|
new promClient.Counter({
|
||||||
|
name: value,
|
||||||
|
help: `Total number of ${properCounterName}`,
|
||||||
|
labelNames: ['status']
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// in addition to the enum counters, add a few more custom counters
|
||||||
|
// version, http_request_duration_ms, http_requests_total
|
||||||
|
const versionGaugeCounter = new promClient.Gauge({
|
||||||
|
name: 'flowise_version_info',
|
||||||
|
help: 'Flowise version info.',
|
||||||
|
labelNames: ['version']
|
||||||
|
})
|
||||||
|
|
||||||
|
const { version } = await getVersion()
|
||||||
|
versionGaugeCounter.set({ version: 'v' + version }, 1)
|
||||||
|
this.counters.set('flowise_version', versionGaugeCounter)
|
||||||
|
|
||||||
|
this.httpRequestDurationMicroseconds = new promClient.Histogram({
|
||||||
|
name: 'http_request_duration_ms',
|
||||||
|
help: 'Duration of HTTP requests in ms',
|
||||||
|
labelNames: ['method', 'route', 'code'],
|
||||||
|
buckets: [1, 5, 15, 50, 100, 200, 300, 400, 500] // buckets for response time from 0.1ms to 500ms
|
||||||
|
})
|
||||||
|
this.counters.set('http_request_duration_ms', this.httpRequestDurationMicroseconds)
|
||||||
|
|
||||||
|
this.requestCounter = new Counter({
|
||||||
|
name: 'http_requests_total',
|
||||||
|
help: 'Total number of HTTP requests',
|
||||||
|
labelNames: ['method', 'path', 'status']
|
||||||
|
})
|
||||||
|
this.counters.set('http_requests_total', this.requestCounter)
|
||||||
|
|
||||||
|
this.registerMetrics()
|
||||||
|
await this.setupMetricsEndpoint()
|
||||||
|
}
|
||||||
|
|
||||||
|
async setupMetricsEndpoint() {
|
||||||
|
// Add Prometheus middleware to the app
|
||||||
|
this.app.use('/api/v1/metrics', async (req, res) => {
|
||||||
|
res.set('Content-Type', this.register.contentType)
|
||||||
|
const currentMetrics = await this.register.metrics()
|
||||||
|
res.send(currentMetrics).end()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Runs before each requests
|
||||||
|
this.app.use((req, res, next) => {
|
||||||
|
res.locals.startEpoch = Date.now()
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Runs after each requests
|
||||||
|
this.app.use((req, res, next) => {
|
||||||
|
res.on('finish', async () => {
|
||||||
|
if (res.locals.startEpoch) {
|
||||||
|
this.requestCounter.inc()
|
||||||
|
const responseTimeInMs = Date.now() - res.locals.startEpoch
|
||||||
|
this.httpRequestDurationMicroseconds
|
||||||
|
.labels(req.method, req.baseUrl, res.statusCode.toString())
|
||||||
|
.observe(responseTimeInMs)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public incrementCounter(counter: FLOWISE_METRIC_COUNTERS, payload: any) {
|
||||||
|
// increment the counter with the payload
|
||||||
|
if (this.counters.has(counter)) {
|
||||||
|
;(this.counters.get(counter) as Counter<string>).labels(payload).inc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private registerMetrics() {
|
||||||
|
if (process.env.METRICS_INCLUDE_NODE_METRICS !== 'false') {
|
||||||
|
// enable default metrics like CPU usage, memory usage, etc.
|
||||||
|
promClient.collectDefaultMetrics({ register: this.register })
|
||||||
|
}
|
||||||
|
// Add our custom metrics to the registry
|
||||||
|
for (const counter of this.counters.values()) {
|
||||||
|
this.register.registerMetric(counter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ import { decryptCredentialData, getAppVersion } from '../../utils'
|
||||||
import { InternalFlowiseError } from '../../errors/internalFlowiseError'
|
import { InternalFlowiseError } from '../../errors/internalFlowiseError'
|
||||||
import { getErrorMessage } from '../../errors/utils'
|
import { getErrorMessage } from '../../errors/utils'
|
||||||
import { DeleteResult } from 'typeorm'
|
import { DeleteResult } from 'typeorm'
|
||||||
|
import { FLOWISE_METRIC_COUNTERS, FLOWISE_COUNTER_STATUS } from '../../Interface.Metrics'
|
||||||
|
|
||||||
const createAssistant = async (requestBody: any): Promise<Assistant> => {
|
const createAssistant = async (requestBody: any): Promise<Assistant> => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -111,6 +112,7 @@ const createAssistant = async (requestBody: any): Promise<Assistant> => {
|
||||||
version: await getAppVersion(),
|
version: await getAppVersion(),
|
||||||
assistantId: dbResponse.id
|
assistantId: dbResponse.id
|
||||||
})
|
})
|
||||||
|
appServer.metricsProvider.incrementCounter(FLOWISE_METRIC_COUNTERS.ASSISTANT_CREATED, { status: FLOWISE_COUNTER_STATUS.SUCCESS })
|
||||||
return dbResponse
|
return dbResponse
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new InternalFlowiseError(
|
throw new InternalFlowiseError(
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import { containsBase64File, updateFlowDataWithFilePaths } from '../../utils/fil
|
||||||
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
|
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
|
||||||
import { utilGetUploadsConfig } from '../../utils/getUploadsConfig'
|
import { utilGetUploadsConfig } from '../../utils/getUploadsConfig'
|
||||||
import logger from '../../utils/logger'
|
import logger from '../../utils/logger'
|
||||||
|
import { FLOWISE_METRIC_COUNTERS, FLOWISE_COUNTER_STATUS } from '../../Interface.Metrics'
|
||||||
|
|
||||||
// Check if chatflow valid for streaming
|
// Check if chatflow valid for streaming
|
||||||
const checkIfChatflowIsValidForStreaming = async (chatflowId: string): Promise<any> => {
|
const checkIfChatflowIsValidForStreaming = async (chatflowId: string): Promise<any> => {
|
||||||
|
|
@ -191,6 +192,11 @@ const saveChatflow = async (newChatFlow: ChatFlow): Promise<any> => {
|
||||||
chatflowId: dbResponse.id,
|
chatflowId: dbResponse.id,
|
||||||
flowGraph: getTelemetryFlowObj(JSON.parse(dbResponse.flowData)?.nodes, JSON.parse(dbResponse.flowData)?.edges)
|
flowGraph: getTelemetryFlowObj(JSON.parse(dbResponse.flowData)?.nodes, JSON.parse(dbResponse.flowData)?.edges)
|
||||||
})
|
})
|
||||||
|
appServer.metricsProvider.incrementCounter(
|
||||||
|
dbResponse?.type === 'MULTIAGENT' ? FLOWISE_METRIC_COUNTERS.AGENTFLOW_CREATED : FLOWISE_METRIC_COUNTERS.CHATFLOW_CREATED,
|
||||||
|
{ status: FLOWISE_COUNTER_STATUS.SUCCESS }
|
||||||
|
)
|
||||||
|
|
||||||
return dbResponse
|
return dbResponse
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new InternalFlowiseError(
|
throw new InternalFlowiseError(
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import { Document } from '@langchain/core/documents'
|
||||||
import { App } from '../../index'
|
import { App } from '../../index'
|
||||||
import { UpsertHistory } from '../../database/entities/UpsertHistory'
|
import { UpsertHistory } from '../../database/entities/UpsertHistory'
|
||||||
import { cloneDeep, omit } from 'lodash'
|
import { cloneDeep, omit } from 'lodash'
|
||||||
import telemetryService from '../telemetry'
|
import { FLOWISE_COUNTER_STATUS, FLOWISE_METRIC_COUNTERS } from '../../Interface.Metrics'
|
||||||
|
|
||||||
const DOCUMENT_STORE_BASE_FOLDER = 'docustore'
|
const DOCUMENT_STORE_BASE_FOLDER = 'docustore'
|
||||||
|
|
||||||
|
|
@ -990,15 +990,13 @@ const _insertIntoVectorStoreWorkerThread = async (data: ICommonObject) => {
|
||||||
await appServer.AppDataSource.getRepository(UpsertHistory).save(upsertHistoryItem)
|
await appServer.AppDataSource.getRepository(UpsertHistory).save(upsertHistoryItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
await telemetryService.createEvent({
|
await appServer.telemetry.sendTelemetry('vector_upserted', {
|
||||||
name: `vector_upserted`,
|
version: await getAppVersion(),
|
||||||
data: {
|
chatlowId: chatflowid,
|
||||||
version: await getAppVersion(),
|
type: ChatType.INTERNAL,
|
||||||
chatlowId: chatflowid,
|
flowGraph: omit(indexResult['result'], ['totalKeys', 'addedDocs'])
|
||||||
type: ChatType.INTERNAL,
|
|
||||||
flowGraph: omit(indexResult['result'], ['totalKeys', 'addedDocs'])
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
appServer.metricsProvider.incrementCounter(FLOWISE_METRIC_COUNTERS.VECTORSTORE_UPSERT, { status: FLOWISE_COUNTER_STATUS.SUCCESS })
|
||||||
|
|
||||||
entity.status = DocumentStoreStatus.UPSERTED
|
entity.status = DocumentStoreStatus.UPSERTED
|
||||||
await appServer.AppDataSource.getRepository(DocumentStore).save(entity)
|
await appServer.AppDataSource.getRepository(DocumentStore).save(entity)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
|
|
||||||
|
|
||||||
const createEvent = async (eventInfo: any) => {
|
|
||||||
const appServer = getRunningExpressApp()
|
|
||||||
await appServer.telemetry.sendTelemetry(eventInfo.name, eventInfo.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
createEvent
|
|
||||||
}
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { InternalFlowiseError } from '../../errors/internalFlowiseError'
|
||||||
import { getErrorMessage } from '../../errors/utils'
|
import { getErrorMessage } from '../../errors/utils'
|
||||||
import { getAppVersion } from '../../utils'
|
import { getAppVersion } from '../../utils'
|
||||||
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
|
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
|
||||||
|
import { FLOWISE_METRIC_COUNTERS, FLOWISE_COUNTER_STATUS } from '../../Interface.Metrics'
|
||||||
|
|
||||||
const createTool = async (requestBody: any): Promise<any> => {
|
const createTool = async (requestBody: any): Promise<any> => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -17,6 +18,7 @@ const createTool = async (requestBody: any): Promise<any> => {
|
||||||
toolId: dbResponse.id,
|
toolId: dbResponse.id,
|
||||||
toolName: dbResponse.name
|
toolName: dbResponse.name
|
||||||
})
|
})
|
||||||
|
appServer.metricsProvider.incrementCounter(FLOWISE_METRIC_COUNTERS.TOOL_CREATED, { status: FLOWISE_COUNTER_STATUS.SUCCESS })
|
||||||
return dbResponse
|
return dbResponse
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, `Error: toolsService.createTool - ${getErrorMessage(error)}`)
|
throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, `Error: toolsService.createTool - ${getErrorMessage(error)}`)
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ import { buildAgentGraph } from './buildAgentGraph'
|
||||||
import { getErrorMessage } from '../errors/utils'
|
import { getErrorMessage } from '../errors/utils'
|
||||||
import { ChatMessage } from '../database/entities/ChatMessage'
|
import { ChatMessage } from '../database/entities/ChatMessage'
|
||||||
import { IAction } from 'flowise-components'
|
import { IAction } from 'flowise-components'
|
||||||
|
import { FLOWISE_METRIC_COUNTERS, FLOWISE_COUNTER_STATUS } from '../Interface.Metrics'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build Chatflow
|
* Build Chatflow
|
||||||
|
|
@ -62,8 +63,8 @@ import { IAction } from 'flowise-components'
|
||||||
* @param {boolean} isInternal
|
* @param {boolean} isInternal
|
||||||
*/
|
*/
|
||||||
export const utilBuildChatflow = async (req: Request, isInternal: boolean = false): Promise<any> => {
|
export const utilBuildChatflow = async (req: Request, isInternal: boolean = false): Promise<any> => {
|
||||||
|
const appServer = getRunningExpressApp()
|
||||||
try {
|
try {
|
||||||
const appServer = getRunningExpressApp()
|
|
||||||
const chatflowid = req.params.id
|
const chatflowid = req.params.id
|
||||||
|
|
||||||
const httpProtocol = req.get('x-forwarded-proto') || req.protocol
|
const httpProtocol = req.get('x-forwarded-proto') || req.protocol
|
||||||
|
|
@ -493,6 +494,10 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
|
||||||
flowGraph: getTelemetryFlowObj(nodes, edges)
|
flowGraph: getTelemetryFlowObj(nodes, edges)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
appServer.metricsProvider.incrementCounter(
|
||||||
|
isInternal ? FLOWISE_METRIC_COUNTERS.CHATFLOW_PREDICTION_INTERNAL : FLOWISE_METRIC_COUNTERS.CHATFLOW_PREDICTION_EXTERNAL,
|
||||||
|
{ status: FLOWISE_COUNTER_STATUS.SUCCESS }
|
||||||
|
)
|
||||||
// Prepare response
|
// Prepare response
|
||||||
// return the question in the response
|
// return the question in the response
|
||||||
// this is used when input text is empty but question is in audio format
|
// this is used when input text is empty but question is in audio format
|
||||||
|
|
@ -507,6 +512,10 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
|
||||||
|
|
||||||
return result
|
return result
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
appServer.metricsProvider.incrementCounter(
|
||||||
|
isInternal ? FLOWISE_METRIC_COUNTERS.CHATFLOW_PREDICTION_INTERNAL : FLOWISE_METRIC_COUNTERS.CHATFLOW_PREDICTION_EXTERNAL,
|
||||||
|
{ status: FLOWISE_COUNTER_STATUS.FAILURE }
|
||||||
|
)
|
||||||
logger.error('[server]: Error:', e)
|
logger.error('[server]: Error:', e)
|
||||||
if (e instanceof InternalFlowiseError && e.statusCode === StatusCodes.UNAUTHORIZED) {
|
if (e instanceof InternalFlowiseError && e.statusCode === StatusCodes.UNAUTHORIZED) {
|
||||||
throw e
|
throw e
|
||||||
|
|
@ -533,8 +542,8 @@ const utilBuildAgentResponse = async (
|
||||||
shouldStreamResponse?: boolean,
|
shouldStreamResponse?: boolean,
|
||||||
uploadedFilesContent?: string
|
uploadedFilesContent?: string
|
||||||
) => {
|
) => {
|
||||||
|
const appServer = getRunningExpressApp()
|
||||||
try {
|
try {
|
||||||
const appServer = getRunningExpressApp()
|
|
||||||
const streamResults = await buildAgentGraph(
|
const streamResults = await buildAgentGraph(
|
||||||
agentflow,
|
agentflow,
|
||||||
chatId,
|
chatId,
|
||||||
|
|
@ -599,6 +608,10 @@ const utilBuildAgentResponse = async (
|
||||||
type: isInternal ? ChatType.INTERNAL : ChatType.EXTERNAL,
|
type: isInternal ? ChatType.INTERNAL : ChatType.EXTERNAL,
|
||||||
flowGraph: getTelemetryFlowObj(nodes, edges)
|
flowGraph: getTelemetryFlowObj(nodes, edges)
|
||||||
})
|
})
|
||||||
|
appServer.metricsProvider.incrementCounter(
|
||||||
|
isInternal ? FLOWISE_METRIC_COUNTERS.AGENTFLOW_PREDICTION_INTERNAL : FLOWISE_METRIC_COUNTERS.AGENTFLOW_PREDICTION_EXTERNAL,
|
||||||
|
{ status: FLOWISE_COUNTER_STATUS.SUCCESS }
|
||||||
|
)
|
||||||
|
|
||||||
// Find the previous chat message with the same action id and remove the action
|
// Find the previous chat message with the same action id and remove the action
|
||||||
if (incomingInput.action && Object.keys(incomingInput.action).length) {
|
if (incomingInput.action && Object.keys(incomingInput.action).length) {
|
||||||
|
|
@ -645,6 +658,10 @@ const utilBuildAgentResponse = async (
|
||||||
return undefined
|
return undefined
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('[server]: Error:', e)
|
logger.error('[server]: Error:', e)
|
||||||
|
appServer.metricsProvider.incrementCounter(
|
||||||
|
isInternal ? FLOWISE_METRIC_COUNTERS.AGENTFLOW_PREDICTION_INTERNAL : FLOWISE_METRIC_COUNTERS.AGENTFLOW_PREDICTION_EXTERNAL,
|
||||||
|
{ status: FLOWISE_COUNTER_STATUS.FAILURE }
|
||||||
|
)
|
||||||
throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, getErrorMessage(e))
|
throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, getErrorMessage(e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import * as fs from 'fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import { cloneDeep, omit } from 'lodash'
|
import { cloneDeep, omit } from 'lodash'
|
||||||
import { ICommonObject, IMessage, addArrayFilesToStorage, mapMimeTypeToInputField, mapExtToInputField } from 'flowise-components'
|
import { ICommonObject, IMessage, addArrayFilesToStorage, mapMimeTypeToInputField, mapExtToInputField } from 'flowise-components'
|
||||||
import telemetryService from '../services/telemetry'
|
|
||||||
import logger from '../utils/logger'
|
import logger from '../utils/logger'
|
||||||
import {
|
import {
|
||||||
buildFlow,
|
buildFlow,
|
||||||
|
|
@ -24,6 +23,7 @@ import { InternalFlowiseError } from '../errors/internalFlowiseError'
|
||||||
import { StatusCodes } from 'http-status-codes'
|
import { StatusCodes } from 'http-status-codes'
|
||||||
import { getErrorMessage } from '../errors/utils'
|
import { getErrorMessage } from '../errors/utils'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import { FLOWISE_COUNTER_STATUS, FLOWISE_METRIC_COUNTERS } from '../Interface.Metrics'
|
||||||
/**
|
/**
|
||||||
* Upsert documents
|
* Upsert documents
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
|
|
@ -190,16 +190,14 @@ export const upsertVector = async (req: Request, isInternal: boolean = false) =>
|
||||||
await appServer.AppDataSource.getRepository(UpsertHistory).save(upsertHistory)
|
await appServer.AppDataSource.getRepository(UpsertHistory).save(upsertHistory)
|
||||||
}
|
}
|
||||||
|
|
||||||
await telemetryService.createEvent({
|
await appServer.telemetry.sendTelemetry('vector_upserted', {
|
||||||
name: `vector_upserted`,
|
version: await getAppVersion(),
|
||||||
data: {
|
chatlowId: chatflowid,
|
||||||
version: await getAppVersion(),
|
type: isInternal ? ChatType.INTERNAL : ChatType.EXTERNAL,
|
||||||
chatlowId: chatflowid,
|
flowGraph: getTelemetryFlowObj(nodes, edges),
|
||||||
type: isInternal ? ChatType.INTERNAL : ChatType.EXTERNAL,
|
stopNodeId
|
||||||
flowGraph: getTelemetryFlowObj(nodes, edges),
|
|
||||||
stopNodeId
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
appServer.metricsProvider.incrementCounter(FLOWISE_METRIC_COUNTERS.VECTORSTORE_UPSERT, { status: FLOWISE_COUNTER_STATUS.SUCCESS })
|
||||||
|
|
||||||
return upsertedResult['result'] ?? { result: 'Successfully Upserted' }
|
return upsertedResult['result'] ?? { result: 'Successfully Upserted' }
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
1306
pnpm-lock.yaml
1306
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue