Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: adding grafana tempo cloud support #1963

Conversation

xoscar
Copy link
Collaborator

@xoscar xoscar commented Feb 9, 2023

This PR adds support for the HTTP client for Grafana Tempo Cloud
It decouples the tempo config from just supporting gRPC and adds HTTP capabilities.

Changes

  • Updates the Tempo config to support the HTTP client
  • Adds section for gRPC and HTTP
  • Implements generic HTTP and gRPC client for the BE
  • Fixes issue with the test connection not supporting URLs with paths

Fixes

Checklist

  • tested locally
  • added new dependencies
  • updated the docs
  • added a test

https://www.loom.com/share/f17a9708c64341ab93e853cd5940c760

@xoscar xoscar linked an issue Feb 9, 2023 that may be closed by this pull request
@xoscar xoscar self-assigned this Feb 9, 2023
@@ -29,6 +29,15 @@ components:
createdAt:
type: string
format: date-time
BaseClient:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Base client supports both http and grpc settings

@@ -149,3 +149,12 @@ services:
condition: service_healthy
queue:
condition: service_healthy

tempo:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding example including tempo

deepcopy.DeepCopy(in.Tempo.Tls, &dataStore.Values.Tempo.TLSSetting)
deepcopy.DeepCopy(in.Tempo.Tls.Settings, &dataStore.Values.Tempo.TLSSetting.TLSSetting)
deepcopy.DeepCopy(in.Tempo.Grpc.Tls, &dataStore.Values.Tempo.Grpc.TLSSetting)
deepcopy.DeepCopy(in.Tempo.Grpc.Tls.Settings, &dataStore.Values.Tempo.Grpc.TLSSetting.TLSSetting)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to fix this at some point as its getting out of hand

type SupportedClients string

var (
GRPC SupportedClients = "grpc"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Main facade to use the http and grpc clients

}

client.conn = conn
return nil
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic grpc client

"crypto/x509"
"errors"
"fmt"
"io"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic http client

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth adding a generic http client? Every api is different and I can't see a benefit in having a generic client for it. I think we would have to make it extremely configurable, and I don't think that's worth the effort.

This might be applicable to the gRPC client too.

@schoren @danielbdias I want your thoughts here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing about having it extremely configurable is that the complexity of the generic client will explode in a little time (for instance, having a lot of ifs and options), that's correct?

To tame that, I was thinking if we can follow something like the strategy design pattern in the future: we could have one client for each DataStore and the data store itself decides how to use communication strategy internally (HTTP and/or gRPC).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mathnogueira the gRPC is pretty much the same thing we were using for both tempo and jaeger just moved to a different file.

For the HTTP one, what things do you expect to keep changing? we already support the basic stuff including TLS.
Another thing is, this implementation is similar to the HTTP trigger one.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danielbdias the initial idea was to build something similar to the strategy pattern, but as this is a double layer (trace db + clients) I think a better way to describe it is as an Abstract Factory.

The situation here is that tracedbs are all similar until the getTraceById step, where each one has a different way of handling that. I can create a data_store interface so each of the clients has the same implementation, and a single callback type

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the code based on the comments, let me know what you think

return false, err
}

endpoint = strings.TrimPrefix(endpoint, "http://")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes an issue with urls like https://tempo-us-central1.grafana.net/tempo

Batches []*traces.HttpResourceSpans `json:"batches"`
}

func httpGetTraceByID(ctx context.Context, traceID string, client client.HttpClient) (model.Trace, error) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding HTTP trace processor

@@ -0,0 +1,112 @@
package traces
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a mismatch between tempo's HTTP response and the actual proto, I had to create this to fix that

const Component = FieldsFormMap[type];

return (
<>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implements switching from HTTP to GRPC

const baseName = ['dataStore', dataStoreType, 'http'];
const insecureValue = Form.useWatch([...baseName, 'tls', 'insecure'], form) ?? true;

return (
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new HTTP client

@@ -1,9 +1,7 @@
import {IGRPCClientSettings, SupportedDataStores, TDataStoreService, TRawGRPCClientSettings} from 'types/Config.types';
import DataStore from 'models/DataStore.model';
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GRPC and HTTP clients are now out of the factory part to be used directly from the BaseClient & JaegerService

@xoscar xoscar marked this pull request as ready for review February 9, 2023 15:52
otlp/2:
endpoint: tempo-us-central1.grafana.net:443
headers:
Authorization: Basic Mzc0OTIzOmV5SnJJam9pTmpFeU1UaGlZalJtTURZM05UUmxaRGt4WmpSaE5UWTNZbVF5WVRKalpEVXdORE0zWWpnMU9DSXNJbTRpT2lKMGNtRmpaWFJsYzNRaUxDSnBaQ0k2TnpnNE5URXdmUT09
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have this secret here?

HTTP HttpCallback
}

type Client struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This naming is difficult to understand because we are referencing as client.Client, which feels like "this is a client for what"? The idea behind it is here: https://github.com/golang/go/wiki/CodeReviewComments#package-names

At first glance, it seems to me something like TraceDataSource. Invoking other golang devs here: @schoren @mathnogueira , it makes sense folks?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like TraceDataSource or just DataSource I'll give it a go, thanks for pointing me to that documentation file ❤️


if value["doubleValue"] != nil {
val := value["doubleValue"].(float64)
if val != 0.0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this comparison will work correctly every time, because of the floating point craziness that we have (like 0.1 * 10 != 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 that we have in some languages like Python and JS).

To check if it is a double here we could do:

val, ok := value["doubleValue"].(float64)
if ok {
  // do stuff of `if val != 0.0`
}

@xoscar
Copy link
Collaborator Author

xoscar commented Feb 9, 2023

Hey @danielbdias thanks for the review my man, I just updated some of the things you mentioned!

@mathnogueira
Copy link
Member

I think it's worth adding an example using the http jaeger poller and add it to our CI

Copy link
Contributor

@jorgeepc jorgeepc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job 🔥

@xoscar xoscar merged commit e659b1d into main Feb 13, 2023
@xoscar xoscar deleted the 1938-datastores-research-connectivity-issues-with-grafana-cloud-tempo branch February 13, 2023 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[DataStores] Research Connectivity issues with Grafana Cloud Tempo
4 participants