core/metrics/localmetrics/jaeger.go
package localmetrics
import (
"context"
"fmt"
"os"
"time"
"github.com/ory/dockertest/v3"
"github.com/ory/dockertest/v3/docker"
"github.com/stretchr/testify/assert"
"github.com/synapsecns/sanguine/core"
"github.com/synapsecns/sanguine/core/dockerutil"
"github.com/synapsecns/sanguine/core/metrics/internal"
"github.com/synapsecns/sanguine/core/processlog"
"github.com/synapsecns/sanguine/core/retry"
)
// StartJaegerServer starts a new jaeger instance.
// nolint: cyclop
func (j *testJaeger) StartJaegerServer(ctx context.Context) *uiResource {
if core.HasEnv(internal.JaegerEndpoint) && !core.HasEnv(internal.JaegerUIEndpoint) {
j.tb.Fatalf("%s is set but %s is not, please remove %s or set %s", internal.JaegerEndpoint, internal.JaegerUIEndpoint, internal.JaegerEndpoint, internal.JaegerUIEndpoint)
}
if core.HasEnv(internal.JaegerEndpoint) {
return &uiResource{
Resource: nil,
uiURL: os.Getenv(internal.JaegerUIEndpoint),
}
}
runOptions := &dockertest.RunOptions{
Repository: "jaegertracing/all-in-one",
Tag: "latest",
Hostname: "jaeger",
ExposedPorts: []string{"14268", "16686"},
Networks: j.getNetworks(),
Labels: map[string]string{
appLabel: "jaeger",
runIDLabel: j.runID,
},
}
resource, err := j.pool.RunWithOptions(runOptions, func(config *docker.HostConfig) {
config.AutoRemove = true
config.RestartPolicy = docker.RestartPolicy{Name: "no"}
})
assert.Nil(j.tb, err)
j.tb.Setenv(internal.JaegerEndpoint, fmt.Sprintf("http://localhost:%s/api/traces", dockerutil.GetPort(resource, "14268/tcp")))
// uiEndpoint is the jaeger endpoint, we want to instead use the pyroscope endpoint
uiEndpoint := fmt.Sprintf("http://localhost:%s", dockerutil.GetPort(resource, "16686/tcp"))
if !j.cfg.keepContainers {
err = resource.Expire(uint(keepAliveOnFailure.Seconds()))
assert.Nil(j.tb, err)
}
logResourceChan := make(chan *uiResource, 1)
go func() {
_ = dockerutil.TailContainerLogs(dockerutil.WithContext(ctx), dockerutil.WithPool(j.pool), dockerutil.WithProcessLogOptions(processlog.WithLogDir(j.logDir), processlog.WithLogFileName("jaeger")), dockerutil.WithFollow(true),
dockerutil.WithResource(resource), dockerutil.WithCallback(func(ctx context.Context, metadata processlog.LogMetadata) {
select {
case <-ctx.Done():
return
case logResourceChan <- &uiResource{
Resource: resource,
uiURL: uiEndpoint,
}:
return
}
}))
}()
// make sure client is alive
err = retry.WithBackoff(ctx, checkURL(os.Getenv(internal.JaegerEndpoint)), retry.WithMax(time.Millisecond*10), retry.WithMax(time.Minute))
if err != nil {
return nil
}
select {
case <-ctx.Done():
return nil
case logResource := <-logResourceChan:
// if pyroscope jaeger is enabled, we'll use that ui otherwise we'll use this one
if !j.cfg.enablePyroscopeJaeger {
err = os.Setenv(internal.JaegerUIEndpoint, logResource.uiURL)
assert.Nil(j.tb, err)
}
return logResource
}
}
// StartJaegerPyroscopeUI starts a new jaeger pyroscope ui instance.
func (j *testJaeger) StartJaegerPyroscopeUI(ctx context.Context) *uiResource {
// can't enable if pyroscope is disabled
// TODO: add a warning here.
if core.HasEnv(internal.JaegerUIEndpoint) || !j.cfg.enablePyroscope {
return &uiResource{
uiURL: os.Getenv(internal.JaegerUIEndpoint),
}
}
// we use this to let pyroscope no to include profiles as span tags
err := os.Setenv(internal.PyroscopeJaegerUIEnabled, "true")
assert.Nil(j.tb, err)
runOptions := &dockertest.RunOptions{
Repository: "ghcr.io/synapsecns/jaeger-ui-pyroscope",
Tag: "latest",
ExposedPorts: []string{"80"},
Networks: j.getNetworks(),
Labels: map[string]string{
appLabel: "jaeger-ui",
runIDLabel: j.runID,
},
}
resource, err := j.pool.RunWithOptions(runOptions, func(config *docker.HostConfig) {
config.AutoRemove = true
config.RestartPolicy = docker.RestartPolicy{Name: "no"}
})
assert.Nil(j.tb, err)
// must only be done after the container is started
j.tb.Setenv(internal.JaegerUIEndpoint, fmt.Sprintf("http://localhost:%s", dockerutil.GetPort(resource, "80/tcp")))
if !j.cfg.keepContainers {
err = resource.Expire(uint(keepAliveOnFailure.Seconds()))
assert.Nil(j.tb, err)
}
logResourceChan := make(chan *uiResource, 1)
go func() {
_ = dockerutil.TailContainerLogs(dockerutil.WithContext(ctx), dockerutil.WithPool(j.pool), dockerutil.WithProcessLogOptions(processlog.WithLogDir(j.logDir), processlog.WithLogFileName("jaeger-pyroscope-ui")), dockerutil.WithFollow(true),
dockerutil.WithResource(resource), dockerutil.WithCallback(func(ctx context.Context, metadata processlog.LogMetadata) {
select {
case <-ctx.Done():
return
case logResourceChan <- &uiResource{
Resource: resource,
uiURL: os.Getenv(internal.JaegerUIEndpoint),
}:
return
}
}))
}()
// make sure client is alive
err = retry.WithBackoff(ctx, checkURL(os.Getenv(internal.JaegerEndpoint)), retry.WithMax(time.Millisecond*10), retry.WithMax(time.Minute))
if err != nil {
return nil
}
select {
case <-ctx.Done():
return nil
case logResource := <-logResourceChan:
return logResource
}
}