Skip to content

Commit a8ddbbf

Browse files
committed
enhanced tracing and logging
1 parent e14e270 commit a8ddbbf

23 files changed

+302
-52
lines changed

.changeset/strong-guests-guess.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'grafana-infinity-datasource': minor
3+
---
4+
5+
Added distributed tracing and contextual logging for dev

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ website/out/
3030
website/next-env.d.ts
3131
work/
3232
yarn-debug.log*
33-
yarn-error.log*
33+
yarn-error.log*
34+
docker/blocks/tempo/tempo-data

CONTRIBUTING.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Once you clone the repo locally in the grafana's plugin folder. Do the following
1818
- `yarn` - This will install the frontend dependencies. Do this once
1919
- `yarn watch` - For continuously watching the front-end changes and build
2020
- `mage -v` - This will help to build the backend part of the plugin. Do this once if you are contributing only the frontend. There is no significant code is in the backend. So no much changes expected
21-
- `docker-compose up` - To run the plugin with grafana locally. ( use infinity:infinity as the credentials )
21+
- `docker-compose up` - To run the plugin with grafana locally. ( use infinity:infinity as the credentials ). You can also enable traces and logs with debug mode. Refer the **Setting up grafana in debug mode** section below
2222
- `yarn test` - To make sure all the existing tests passed
2323

2424
## Setting up the plugin docs site locally
@@ -33,3 +33,8 @@ If you are creating a PR, ensure to run `yarn changeset` from your branch. Provi
3333
## Releasing & Bumping version
3434

3535
To create a new release, execute `yarn changeset version`. This will update the Changelog and bump the version in `package.json` file. Commit those changes and then create a release tag by executing `git tag v1.4.1`. Then you can push the commit and tag by executing `git push && git push --tags`
36+
37+
## Setting up grafana in debug mode
38+
39+
- Ensure the loki docker plugin is installed `docker plugin install grafana/loki-docker-driver:2.9.1 --alias loki --grant-all-permissions`
40+
- Start the docker from debug file `docker compose -f docker-compose-debug.yaml up`

docker-compose-debug.yaml

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
version: '3.7'
2+
x-logging: &default-logging
3+
driver: loki
4+
options:
5+
loki-url: 'http://localhost:3100/api/prom/push'
6+
services:
7+
loki:
8+
image: grafana/loki:main
9+
command: -config.file=/etc/loki/loki-config.yaml
10+
volumes:
11+
- ./docker/blocks/loki/config.yaml:/etc/loki/loki-config.yaml
12+
ports:
13+
- "3100:3100"
14+
tempo:
15+
image: grafana/tempo:latest
16+
depends_on:
17+
- loki
18+
command:
19+
- --config.file=/etc/tempo.yaml
20+
volumes:
21+
- ./docker/blocks/tempo/config.yaml:/etc/tempo.yaml
22+
ports:
23+
- "14268:14268" # jaeger ingest
24+
- "3200:3200" # tempo
25+
- "4317:4317" # otlp grpc
26+
- "4318:4318" # otlp http
27+
grafana:
28+
container_name: yesoreyeram-infinity-datasource
29+
logging: *default-logging
30+
image: grafana/grafana-enterprise:${GF_VERSION:-main}
31+
# image: grafana/grafana-enterprise:${GF_VERSION:-latest}
32+
# image: grafana/grafana-enterprise:${GF_VERSION:-9.4.3}
33+
# image: grafana/grafana-enterprise:${GF_VERSION:-8.4.7}
34+
depends_on:
35+
- loki
36+
- tempo
37+
ports:
38+
- '3000:3000'
39+
volumes:
40+
- ./provisioning/dashboards-actual/:/dashboards/
41+
- ./provisioning:/etc/grafana/provisioning
42+
- ./dist/:/var/lib/grafana/plugins/yesoreyeram-infinity-datasource
43+
environment:
44+
- TERM=linux
45+
- GF_DEFAULT_APP_MODE=development
46+
- GF_AUTH_ANONYMOUS_ENABLED=true
47+
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
48+
- GF_SECURITY_ADMIN_USER=infinity
49+
- GF_SECURITY_ADMIN_PASSWORD=infinity
50+
- GF_SECURITY_ANGULAR_SUPPORT_ENABLED=false
51+
- GF_SECURITY_CSRF_ALWAYS_CHECK=true
52+
- GF_ENTERPRISE_LICENSE_TEXT=$GF_ENTERPRISE_LICENSE_TEXT
53+
# - GF_FEATURE_TOGGLES_ENABLE=trimDefaults disableEnvelopeEncryption database_metrics live-service-web-workerqueryOverLive panelTitleSearch prometheusAzureOverrideAudience publicDashboards publicDashboardsEmailSharing lokiLive featureHighlights migrationLocking storage exploreMixedDatasource newTraceViewHeader correlations cloudWatchDynamicLabels datasourceQueryMultiStatus traceToMetrics newDBLibrary validateDashboardsOnSave autoMigrateOldPanels disableAngular prometheusWideSeries canvasPanelNesting scenes disableSecretsCompatibility logRequestsInstrumentedAsUnknown dataConnectionsConsole internationalization topnav grpcServer entityStore cloudWatchCrossAccountQuerying redshiftAsyncQueryDataSupport athenaAsyncQueryDataSupport newPanelChromeUI showDashboardValidationWarnings mysqlAnsiQuotes accessControlOnCall nestedFolders accessTokenExpirationCheck showTraceId datasourceOnboarding emptyDashboardPage authnService disablePrometheusExemplarSampling alertingBacktesting editPanelCSVDragAndDrop alertingNoNormalState logsSampleInExplore logsContextDatasourceUi lokiQuerySplitting lokiQuerySplittingConfig individualCookiePreferences onlyExternalOrgRoleSync traceqlSearch prometheusMetricEncyclopedia timeSeriesTable prometheusResourceBrowserCache influxdbBackendMigration clientTokenRotation prometheusDataplane lokiMetricDataplane dataplaneFrontendFallback disableSSEDataplane alertStateHistoryLokiSecondary alertStateHistoryLokiPrimary alertStateHistoryLokiOnly unifiedRequestLog renderAuthJWT pyroscopeFlameGraph externalServiceAuth useCachingService enableElasticsearchBackendQuerying authenticationConfigUI pluginsAPIManifestKey advancedDataSourcePicker opensearchDetectVersion enableDatagridEditing
54+
- GF_FEATURE_TOGGLES_ENABLE=publicDashboards topnav dataConnectionsConsole newPanelChromeUI emptyDashboardPage correlations nestedFolders advancedDataSourcePicker
55+
- GF_PLUGIN_YESOREYERAM_INFINITY_DATASOURCE_TRACING=true
56+
- GF_TRACING_OPENTELEMETRY_OTLP_ADDRESS=tempo:4317
57+
- GF_TRACING_OPENTELEMETRY_OTLP_PROPAGATION=w3c,jaeger
58+
- GF_INSTANCE_OTLP_ADDRESS=tempo:4317
59+
- GF_INSTANCE_OTLP_PROPAGATION=w3c,jaeger

docker-compose.yaml

+1-8
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ services:
33
grafana:
44
container_name: yesoreyeram-infinity-datasource
55
image: grafana/grafana-enterprise:${GF_VERSION:-main}
6-
# image: grafana/grafana-enterprise:${GF_VERSION:-latest}
7-
# image: grafana/grafana-enterprise:${GF_VERSION:-9.4.3}
8-
# image: grafana/grafana-enterprise:${GF_VERSION:-8.4.7}
96
ports:
107
- '3000:3000'
118
volumes:
@@ -22,8 +19,4 @@ services:
2219
- GF_SECURITY_ANGULAR_SUPPORT_ENABLED=false
2320
- GF_SECURITY_CSRF_ALWAYS_CHECK=true
2421
- GF_ENTERPRISE_LICENSE_TEXT=$GF_ENTERPRISE_LICENSE_TEXT
25-
# - GF_FEATURE_TOGGLES_ENABLE=trimDefaults disableEnvelopeEncryption database_metrics live-service-web-workerqueryOverLive panelTitleSearch prometheusAzureOverrideAudience publicDashboards publicDashboardsEmailSharing lokiLive featureHighlights migrationLocking storage exploreMixedDatasource newTraceViewHeader correlations cloudWatchDynamicLabels datasourceQueryMultiStatus traceToMetrics newDBLibrary validateDashboardsOnSave autoMigrateOldPanels disableAngular prometheusWideSeries canvasPanelNesting scenes disableSecretsCompatibility logRequestsInstrumentedAsUnknown dataConnectionsConsole internationalization topnav grpcServer entityStore cloudWatchCrossAccountQuerying redshiftAsyncQueryDataSupport athenaAsyncQueryDataSupport newPanelChromeUI showDashboardValidationWarnings mysqlAnsiQuotes accessControlOnCall nestedFolders accessTokenExpirationCheck showTraceId datasourceOnboarding emptyDashboardPage authnService disablePrometheusExemplarSampling alertingBacktesting editPanelCSVDragAndDrop alertingNoNormalState logsSampleInExplore logsContextDatasourceUi lokiQuerySplitting lokiQuerySplittingConfig individualCookiePreferences onlyExternalOrgRoleSync traceqlSearch prometheusMetricEncyclopedia timeSeriesTable prometheusResourceBrowserCache influxdbBackendMigration clientTokenRotation prometheusDataplane lokiMetricDataplane dataplaneFrontendFallback disableSSEDataplane alertStateHistoryLokiSecondary alertStateHistoryLokiPrimary alertStateHistoryLokiOnly unifiedRequestLog renderAuthJWT pyroscopeFlameGraph externalServiceAuth useCachingService enableElasticsearchBackendQuerying authenticationConfigUI pluginsAPIManifestKey advancedDataSourcePicker opensearchDetectVersion enableDatagridEditing
26-
- GF_FEATURE_TOGGLES_ENABLE=publicDashboards topnav dataConnectionsConsole newPanelChromeUI emptyDashboardPage correlations nestedFolders advancedDataSourcePicker
27-
- GF_PLUGIN_YESOREYERAM_INFINITY_DATASOURCE_TRACING=true
28-
- GF_INSTANCE_OTLP_ADDRESS=${GF_INSTANCE_OTLP_ADDRESS:-foo}
29-
- GF_INSTANCE_OTLP_PROPAGATION=${GF_INSTANCE_OTLP_PROPAGATION:-w3c}
22+

docker/blocks/loki/config.yaml

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
auth_enabled: false
2+
3+
server:
4+
http_listen_port: 3100
5+
grpc_listen_port: 9096
6+
7+
common:
8+
path_prefix: /tmp/loki
9+
storage:
10+
filesystem:
11+
chunks_directory: /tmp/loki/chunks
12+
rules_directory: /tmp/loki/rules
13+
replication_factor: 1
14+
ring:
15+
instance_addr: 127.0.0.1
16+
kvstore:
17+
store: inmemory
18+
19+
schema_config:
20+
configs:
21+
- from: 2020-10-24
22+
store: tsdb
23+
object_store: filesystem
24+
schema: v13
25+
index:
26+
prefix: index_
27+
period: 24h
28+
29+
ruler:
30+
alertmanager_url: http://localhost:9093
31+
32+
ingester:
33+
chunk_target_size: 1000
34+
max_chunk_age: 10s
35+
chunk_idle_period: 10s
36+
flush_check_period: 10s
37+
38+
limits_config:
39+
allow_structured_metadata: true
40+
# By default, Loki will send anonymous, but uniquely-identifiable usage and configuration
41+
# analytics to Grafana Labs. These statistics are sent to https://stats.grafana.org/
42+
#
43+
# Statistics help us better understand how Loki is used, and they show us performance
44+
# levels for most users. This helps us prioritize features and documentation.
45+
# For more information on what's sent, look at
46+
# https://github.com/grafana/loki/blob/main/pkg/usagestats/stats.go
47+
# Refer to the buildReport method to see what goes into a report.
48+
#
49+
# If you would like to disable reporting, uncomment the following lines:
50+
#analytics:
51+
# reporting_enabled: false

docker/blocks/tempo/config.yaml

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
server:
2+
http_listen_port: 3200
3+
4+
distributor:
5+
receivers: # this configuration will listen on all ports and protocols that tempo is capable of.
6+
jaeger: # the receives all come from the OpenTelemetry collector. more configuration information can
7+
protocols: # be found there: https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver
8+
thrift_http: #
9+
grpc: # for a production deployment you should only enable the receivers you need!
10+
thrift_binary:
11+
thrift_compact:
12+
zipkin:
13+
otlp:
14+
protocols:
15+
http:
16+
grpc:
17+
opencensus:
18+
19+
compactor:
20+
compaction:
21+
compaction_window: 1h # blocks in this time window will be compacted together
22+
max_block_bytes: 100_000_000 # maximum size of compacted blocks
23+
block_retention: 1h
24+
compacted_block_retention: 10m
25+
26+
metrics_generator:
27+
traces_storage:
28+
path: /tmp/tempo/generator/traces
29+
registry:
30+
external_labels:
31+
source: tempo
32+
cluster: docker-compose
33+
storage:
34+
path: /tmp/tempo/generator/wal
35+
remote_write:
36+
- url: http://prometheus:9090/api/v1/write
37+
send_exemplars: true
38+
39+
storage:
40+
trace:
41+
backend: local # backend configuration to use
42+
block:
43+
bloom_filter_false_positive: .05 # bloom filter false positive rate. lower values create larger filters but fewer false positives
44+
v2_index_downsample_bytes: 1000 # number of bytes per index record
45+
v2_encoding: zstd # block encoding/compression. options: none, gzip, lz4-64k, lz4-256k, lz4-1M, lz4, snappy, zstd, s2
46+
version: vParquet
47+
wal:
48+
path: /tmp/tempo/wal # where to store the the wal locally
49+
v2_encoding: snappy # wal encoding/compression. options: none, gzip, lz4-64k, lz4-256k, lz4-1M, lz4, snappy, zstd, s2
50+
local:
51+
path: /tmp/tempo/blocks
52+
53+
overrides:
54+
metrics_generator_processors: [local-blocks, service-graphs, span-metrics]
55+
56+
stream_over_http_enabled: true

pkg/infinity/client.go

+15-6
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func GetTLSConfigFromSettings(settings models.InfinitySettings) (*tls.Config, er
5454
return tlsConfig, nil
5555
}
5656

57-
func getBaseHTTPClient(settings models.InfinitySettings) *http.Client {
57+
func getBaseHTTPClient(ctx context.Context, settings models.InfinitySettings) *http.Client {
5858
tlsConfig, err := GetTLSConfigFromSettings(settings)
5959
if err != nil {
6060
return nil
@@ -81,6 +81,8 @@ func getBaseHTTPClient(settings models.InfinitySettings) *http.Client {
8181
}
8282

8383
func NewClient(ctx context.Context, settings models.InfinitySettings) (client *Client, err error) {
84+
_, span := tracing.DefaultTracer().Start(ctx, "NewClient")
85+
defer span.End()
8486
if settings.AuthenticationMethod == "" {
8587
settings.AuthenticationMethod = models.AuthenticationMethodNone
8688
if settings.BasicAuthEnabled {
@@ -90,21 +92,24 @@ func NewClient(ctx context.Context, settings models.InfinitySettings) (client *C
9092
settings.AuthenticationMethod = models.AuthenticationMethodForwardOauth
9193
}
9294
}
93-
httpClient := getBaseHTTPClient(settings)
95+
httpClient := getBaseHTTPClient(ctx, settings)
9496
if httpClient == nil {
97+
span.RecordError(errors.New("invalid http client"))
9598
return nil, errors.New("invalid http client")
9699
}
97-
httpClient = ApplyDigestAuth(httpClient, settings)
98-
httpClient = ApplyOAuthClientCredentials(httpClient, settings)
99-
httpClient = ApplyOAuthJWT(httpClient, settings)
100-
httpClient = ApplyAWSAuth(httpClient, settings)
100+
httpClient = ApplyDigestAuth(ctx, httpClient, settings)
101+
httpClient = ApplyOAuthClientCredentials(ctx, httpClient, settings)
102+
httpClient = ApplyOAuthJWT(ctx, httpClient, settings)
103+
httpClient = ApplyAWSAuth(ctx, httpClient, settings)
101104
client = &Client{
102105
Settings: settings,
103106
HttpClient: httpClient,
104107
}
105108
if settings.AuthenticationMethod == models.AuthenticationMethodAzureBlob {
106109
cred, err := azblob.NewSharedKeyCredential(settings.AzureBlobAccountName, settings.AzureBlobAccountKey)
107110
if err != nil {
111+
span.RecordError(err)
112+
span.SetStatus(500, err.Error())
108113
return nil, fmt.Errorf("invalid azure blob credentials. %s", err)
109114
}
110115
clientUrl := "https://%s.blob.core.windows.net/"
@@ -116,9 +121,13 @@ func NewClient(ctx context.Context, settings models.InfinitySettings) (client *C
116121
}
117122
azClient, err := azblob.NewClientWithSharedKeyCredential(clientUrl, cred, nil)
118123
if err != nil {
124+
span.RecordError(err)
125+
span.SetStatus(500, err.Error())
119126
return nil, fmt.Errorf("invalid azure blob client. %s", err)
120127
}
121128
if azClient == nil {
129+
span.RecordError(errors.New("invalid/empty azure blob client"))
130+
span.SetStatus(500, "invalid/empty azure blob client")
122131
return nil, errors.New("invalid/empty azure blob client")
123132
}
124133
client.AzureBlobClient = azClient

pkg/infinity/csvBackend.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
package infinity
22

33
import (
4+
"context"
5+
6+
"github.com/grafana/grafana-plugin-sdk-go/backend/tracing"
47
"github.com/grafana/grafana-plugin-sdk-go/data"
58
"github.com/yesoreyeram/grafana-infinity-datasource/pkg/models"
69
"github.com/yesoreyeram/grafana-plugins/lib/go/csvframer"
710
"github.com/yesoreyeram/grafana-plugins/lib/go/gframer"
811
)
912

10-
func GetCSVBackendResponse(responseString string, query models.Query) (*data.Frame, error) {
13+
func GetCSVBackendResponse(ctx context.Context, responseString string, query models.Query) (*data.Frame, error) {
14+
_, span := tracing.DefaultTracer().Start(ctx, "GetCSVBackendResponse")
15+
defer span.End()
1116
frame := GetDummyFrame(query)
1217
columns := []gframer.ColumnSelector{}
1318
for _, c := range query.Columns {

pkg/infinity/inline.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"github.com/yesoreyeram/grafana-plugins/lib/go/jsonframer"
1010
)
1111

12-
func GetFrameForInlineSources(query models.Query) (*data.Frame, error) {
12+
func GetFrameForInlineSources(ctx context.Context, query models.Query) (*data.Frame, error) {
1313
frame := GetDummyFrame(query)
1414
if query.Type == models.QueryTypeGROQ || query.Type == models.QueryTypeUQL {
1515
return frame, nil
@@ -19,17 +19,17 @@ func GetFrameForInlineSources(query models.Query) (*data.Frame, error) {
1919
}
2020
switch query.Type {
2121
case models.QueryTypeCSV, models.QueryTypeTSV:
22-
frame, err := GetCSVBackendResponse(query.Data, query)
22+
frame, err := GetCSVBackendResponse(ctx, query.Data, query)
2323
if err != nil {
2424
return frame, err
2525
}
26-
return PostProcessFrame(context.Background(), frame, query)
26+
return PostProcessFrame(ctx, frame, query)
2727
case models.QueryTypeXML, models.QueryTypeHTML:
28-
frame, err := GetXMLBackendResponse(query.Data, query)
28+
frame, err := GetXMLBackendResponse(ctx, query.Data, query)
2929
if err != nil {
3030
return frame, err
3131
}
32-
return PostProcessFrame(context.Background(), frame, query)
32+
return PostProcessFrame(ctx, frame, query)
3333
case models.QueryTypeJSON, models.QueryTypeGraphQL:
3434
columns := []jsonframer.ColumnSelector{}
3535
for _, c := range query.Columns {
@@ -51,7 +51,7 @@ func GetFrameForInlineSources(query models.Query) (*data.Frame, error) {
5151
if newFrame != nil {
5252
frame.Fields = append(frame.Fields, newFrame.Fields...)
5353
}
54-
return PostProcessFrame(context.Background(), frame, query)
54+
return PostProcessFrame(ctx, frame, query)
5555
default:
5656
return frame, errors.New("unknown backend query type")
5757
}

pkg/infinity/jsonBackend.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
package infinity
22

33
import (
4+
"context"
45
"encoding/json"
56
"fmt"
67

78
"github.com/grafana/grafana-plugin-sdk-go/backend"
9+
"github.com/grafana/grafana-plugin-sdk-go/backend/tracing"
810
"github.com/grafana/grafana-plugin-sdk-go/data"
911
"github.com/yesoreyeram/grafana-infinity-datasource/pkg/models"
1012
"github.com/yesoreyeram/grafana-plugins/lib/go/jsonframer"
1113
)
1214

13-
func GetJSONBackendResponse(urlResponseObject any, query models.Query) (*data.Frame, error) {
15+
func GetJSONBackendResponse(ctx context.Context, urlResponseObject any, query models.Query) (*data.Frame, error) {
16+
_, span := tracing.DefaultTracer().Start(ctx, "GetJSONBackendResponse")
17+
defer span.End()
1418
frame := GetDummyFrame(query)
1519
responseString, err := json.Marshal(urlResponseObject)
1620
if err != nil {

0 commit comments

Comments
 (0)