From dceb5e2946bf8b7eafffd218b43f29a154a40c72 Mon Sep 17 00:00:00 2001 From: marcel-dempers Date: Thu, 27 May 2021 13:42:24 +1000 Subject: [PATCH] tracing optimizations + netcore examples --- tracing/README.md | 4 +- tracing/applications-go/playlists-api/app.go | 12 +- .../videos-api-netcore/deploy.yaml | 65 +++++++++++ .../videos-api-netcore/dockerfile | 16 +++ .../src/Controllers/VideosController.cs | 75 +++++++++++++ .../videos-api-netcore/src/Program.cs | 32 ++++++ .../src/Properties/launchSettings.json | 31 ++++++ .../videos-api-netcore/src/Startup.cs | 103 ++++++++++++++++++ .../videos-api-netcore/src/Videos.cs | 13 +++ .../src/appsettings.Development.json | 9 ++ .../videos-api-netcore/src/appsettings.json | 10 ++ .../videos-api-netcore/src/videos-api.csproj | 15 +++ tracing/applications-go/videos-api/app.go | 7 +- tracing/docker-compose.yaml | 21 ++++ 14 files changed, 403 insertions(+), 10 deletions(-) create mode 100644 tracing/applications-go/videos-api-netcore/deploy.yaml create mode 100644 tracing/applications-go/videos-api-netcore/dockerfile create mode 100644 tracing/applications-go/videos-api-netcore/src/Controllers/VideosController.cs create mode 100644 tracing/applications-go/videos-api-netcore/src/Program.cs create mode 100644 tracing/applications-go/videos-api-netcore/src/Properties/launchSettings.json create mode 100644 tracing/applications-go/videos-api-netcore/src/Startup.cs create mode 100644 tracing/applications-go/videos-api-netcore/src/Videos.cs create mode 100644 tracing/applications-go/videos-api-netcore/src/appsettings.Development.json create mode 100644 tracing/applications-go/videos-api-netcore/src/appsettings.json create mode 100644 tracing/applications-go/videos-api-netcore/src/videos-api.csproj diff --git a/tracing/README.md b/tracing/README.md index f615b826d..57025d95c 100644 --- a/tracing/README.md +++ b/tracing/README.md @@ -105,13 +105,13 @@ This is intentional to demonstrate a busy network. +------------+ +---------------+ +--------------+ | videos-web +---->+ playlists-api +--->+ playlists-db | -| | | | | | +| | | | | [redis] | +------------+ +-----+---------+ +--------------+ | v +-----+------+ +-----------+ | videos-api +------>+ videos-db | - | | | | + | | | [redis] | +------------+ +-----------+ ``` diff --git a/tracing/applications-go/playlists-api/app.go b/tracing/applications-go/playlists-api/app.go index d5d6850dc..84100801d 100644 --- a/tracing/applications-go/playlists-api/app.go +++ b/tracing/applications-go/playlists-api/app.go @@ -23,6 +23,8 @@ const serviceName = "playlists-api" var environment = os.Getenv("ENVIRONMENT") var redis_host = os.Getenv("REDIS_HOST") var redis_port = os.Getenv("REDIS_PORT") +var jaeger_host_port = os.Getenv("JAEGER_HOST_PORT") + var ctx = context.Background() var rdb *redis.Client @@ -40,7 +42,7 @@ func main() { // Log the emitted spans to stdout. Reporter: &config.ReporterConfig{ LogSpans: true, - LocalAgentHostPort: "jaeger:6831", + LocalAgentHostPort: jaeger_host_port, }, } @@ -60,7 +62,7 @@ func main() { opentracing.HTTPHeadersCarrier(r.Header), ) - span := tracer.StartSpan("/ GET", ext.RPCServerOption(spanCtx)) + span := tracer.StartSpan("playlists-api: GET /", ext.RPCServerOption(spanCtx)) defer span.Finish() cors(w) @@ -80,7 +82,7 @@ func main() { vs := []videos{} for vi := range playlists[pi].Videos { - span, _ := opentracing.StartSpanFromContext(ctx, "videos-api GET") + span, _ := opentracing.StartSpanFromContext(ctx, "playlists-api: videos-api GET /id") v := videos{} @@ -96,8 +98,8 @@ func main() { ) videoResp, err :=http.DefaultClient.Do(req) - span.Finish() + if err != nil { fmt.Println(err) span.SetTag("error", true) @@ -149,7 +151,7 @@ func main() { func getPlaylists(ctx context.Context)(response string){ - span, _ := opentracing.StartSpanFromContext(ctx, "redis-get") + span, _ := opentracing.StartSpanFromContext(ctx, "playlists-api: redis-get") defer span.Finish() playlistData, err := rdb.Get(ctx, "playlists").Result() diff --git a/tracing/applications-go/videos-api-netcore/deploy.yaml b/tracing/applications-go/videos-api-netcore/deploy.yaml new file mode 100644 index 000000000..57599c3c5 --- /dev/null +++ b/tracing/applications-go/videos-api-netcore/deploy.yaml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: videos-api + labels: + app: videos-api +spec: + selector: + matchLabels: + app: videos-api + replicas: 1 + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + template: + metadata: + labels: + app: videos-api + spec: + containers: + - name: videos-api + image: aimvector/jaeger-tracing:videos-api-netcore-1.0.0 + imagePullPolicy : Always + ports: + - containerPort: 10010 + env: + - name: "ENVIRONMENT" + value: "DEBUG" + - name: "REDIS_HOST" + value: "videos-db" + - name: "REDIS_PORT" + value: "6379" + - name: "JAEGER_AGENT_HOST" + value: "jaeger" + - name: "JAEGER_AGENT_PORT" + value: "6831" + - name: "JAEGER_SERVICE_NAME" + value: "videos-api" + - name: "JAEGER_REPORTER_LOG_SPANS" + value: "true" + - name: "JAEGER_SAMPLER_TYPE" + value: "const" + - name: "JAEGER_PROPAGATION" + value: "jaeger" +--- +apiVersion: v1 +kind: Service +metadata: + name: videos-api + labels: + app: videos-api +spec: + type: ClusterIP + selector: + app: videos-api + ports: + - protocol: TCP + name: http + port: 10010 + targetPort: 10010 +--- + + diff --git a/tracing/applications-go/videos-api-netcore/dockerfile b/tracing/applications-go/videos-api-netcore/dockerfile new file mode 100644 index 000000000..fa4184d04 --- /dev/null +++ b/tracing/applications-go/videos-api-netcore/dockerfile @@ -0,0 +1,16 @@ +#docker run -it -v ${PWD}:/work -p 5000:5000 -w /work aimvector/jaeger-tracing:videos-api-netcore-1.0.0 bash +FROM mcr.microsoft.com/dotnet/sdk:5.0 as dev + +WORKDIR /work/ + +FROM mcr.microsoft.com/dotnet/sdk:5.0 as build + +WORKDIR /work/ +COPY ./src/videos-api.csproj /work/videos-api.csproj +RUN dotnet restore + +COPY ./src/ /work/ +RUN mkdir /out/ +RUN dotnet publish --no-restore --output /out/ --configuration Release + +ENTRYPOINT ["dotnet", "run"] \ No newline at end of file diff --git a/tracing/applications-go/videos-api-netcore/src/Controllers/VideosController.cs b/tracing/applications-go/videos-api-netcore/src/Controllers/VideosController.cs new file mode 100644 index 000000000..ef3710ed9 --- /dev/null +++ b/tracing/applications-go/videos-api-netcore/src/Controllers/VideosController.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using StackExchange.Redis; +using System.Text.Json; +using System.Text.Json.Serialization; +using OpenTracing; +using OpenTracing.Propagation; + +namespace videos_api.Controllers +{ + [ApiController] + [Route("")] + public class VideosController : ControllerBase + { + private readonly ITracer _tracer; + private readonly string _redisHost; + private readonly string _redisPort; + private readonly ConnectionMultiplexer _redis; + private readonly ILogger _logger; + private readonly JsonSerializerOptions _serializationOptions; + + public VideosController(ILogger logger, ITracer tracer) + { + _redisHost = Environment.GetEnvironmentVariable("REDIS_HOST"); + _redisPort = Environment.GetEnvironmentVariable("REDIS_PORT"); + _redis = ConnectionMultiplexer.Connect(_redisHost + ":" + _redisPort); + _logger = logger; + _tracer = tracer ?? throw new ArgumentNullException(nameof(tracer)); + + _serializationOptions = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true + }; + } + + [HttpGet] + [Route("/{id}")] + public Videos Get(string id) + { + ISpanContext traceContext = _tracer.Extract(BuiltinFormats.HttpHeaders, new TextMapExtractAdapter(GetHeaders())); + + string videoContent; + + using (var scope = _tracer.BuildSpan("videos-api-net: redis-get") + .AsChildOf(traceContext) + .StartActive(true)) + { + + + + IDatabase db = _redis.GetDatabase(); + videoContent = db.StringGet(id); + } + + var video = JsonSerializer.Deserialize(videoContent,_serializationOptions); + return video; + + } + + public Dictionary GetHeaders() + { + var headers = new Dictionary(); + foreach (var header in Request.Headers) + { + headers.Add(header.Key, header.Value); + } + + return headers; + } + } +} diff --git a/tracing/applications-go/videos-api-netcore/src/Program.cs b/tracing/applications-go/videos-api-netcore/src/Program.cs new file mode 100644 index 000000000..c5e5becd0 --- /dev/null +++ b/tracing/applications-go/videos-api-netcore/src/Program.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace videos_api +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureLogging(logging => + { + logging.ClearProviders(); + logging.AddConsole(); + }) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseUrls("http://*:10010"); + webBuilder.UseStartup(); + }); + } +} diff --git a/tracing/applications-go/videos-api-netcore/src/Properties/launchSettings.json b/tracing/applications-go/videos-api-netcore/src/Properties/launchSettings.json new file mode 100644 index 000000000..af451ab50 --- /dev/null +++ b/tracing/applications-go/videos-api-netcore/src/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:27460", + "sslPort": 44312 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "videos_api": { + "commandName": "Project", + "dotnetRunMessages": "true", + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/tracing/applications-go/videos-api-netcore/src/Startup.cs b/tracing/applications-go/videos-api-netcore/src/Startup.cs new file mode 100644 index 000000000..fd0e5c533 --- /dev/null +++ b/tracing/applications-go/videos-api-netcore/src/Startup.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.OpenApi.Models; +using Jaeger; +using Jaeger.Reporters; +using Jaeger.Samplers; +using Jaeger.Senders; +using Jaeger.Senders.Thrift; +using OpenTracing; +using OpenTracing.Contrib.NetCore.Configuration; +using OpenTracing.Util; + + +namespace videos_api +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddLogging(loggingBuilder => + { + loggingBuilder.AddConfiguration(Configuration.GetSection("Logging")); + loggingBuilder.AddConsole(); + loggingBuilder.AddDebug(); + }); + + services.AddSingleton(serviceProvider => + { + ILoggerFactory loggerFactory = serviceProvider.GetRequiredService(); + Jaeger.Configuration.SenderConfiguration.DefaultSenderResolver = new SenderResolver(loggerFactory) + .RegisterSenderFactory(); + + var config = Jaeger.Configuration.FromEnv(loggerFactory); + ITracer tracer = config.GetTracer(); + GlobalTracer.Register(tracer); + return tracer; + + // var loggerFactory = serviceProvider.GetRequiredService(); + // var sampler = new ConstSampler(sample: true); + + // var tracer = new Tracer.Builder("videos-api") + // .WithReporter( + // new RemoteReporter.Builder() + // .WithLoggerFactory(loggerFactory) + // .WithSender( + // new UdpSender("jaeger", 6831, 0)) + // .Build()) + // .WithLoggerFactory(loggerFactory) + // .WithSampler(sampler) + // .Build(); + + // GlobalTracer.Register(tracer); + // return tracer; + + }); + + services.AddOpenTracing(); + + services.AddControllers(); + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "videos_api", Version = "v1" }); + }); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + app.UseSwagger(); + app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "videos_api v1")); + } + + app.UseHttpsRedirection(); + app.UseRouting(); + app.UseAuthorization(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + } +} diff --git a/tracing/applications-go/videos-api-netcore/src/Videos.cs b/tracing/applications-go/videos-api-netcore/src/Videos.cs new file mode 100644 index 000000000..201ca9e35 --- /dev/null +++ b/tracing/applications-go/videos-api-netcore/src/Videos.cs @@ -0,0 +1,13 @@ +using System; + +namespace videos_api +{ + public class Videos + { + public string Id { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public string Imageurl { get; set; } + public string Url { get; set; } + } +} diff --git a/tracing/applications-go/videos-api-netcore/src/appsettings.Development.json b/tracing/applications-go/videos-api-netcore/src/appsettings.Development.json new file mode 100644 index 000000000..dba68eb12 --- /dev/null +++ b/tracing/applications-go/videos-api-netcore/src/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/tracing/applications-go/videos-api-netcore/src/appsettings.json b/tracing/applications-go/videos-api-netcore/src/appsettings.json new file mode 100644 index 000000000..81ff87771 --- /dev/null +++ b/tracing/applications-go/videos-api-netcore/src/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +} diff --git a/tracing/applications-go/videos-api-netcore/src/videos-api.csproj b/tracing/applications-go/videos-api-netcore/src/videos-api.csproj new file mode 100644 index 000000000..b88aefbae --- /dev/null +++ b/tracing/applications-go/videos-api-netcore/src/videos-api.csproj @@ -0,0 +1,15 @@ + + + + net5.0 + videos_api + + + + + + + + + + diff --git a/tracing/applications-go/videos-api/app.go b/tracing/applications-go/videos-api/app.go index 9ad8ec8e7..6e5ae37d3 100644 --- a/tracing/applications-go/videos-api/app.go +++ b/tracing/applications-go/videos-api/app.go @@ -25,6 +25,7 @@ const serviceName = "videos-api" var environment = os.Getenv("ENVIRONMENT") var redis_host = os.Getenv("REDIS_HOST") var redis_port = os.Getenv("REDIS_PORT") +var jaeger_host_port = os.Getenv("JAEGER_HOST_PORT") var flaky = os.Getenv("FLAKY") var delay = os.Getenv("DELAY") @@ -45,7 +46,7 @@ func main() { // Log the emitted spans to stdout. Reporter: &config.ReporterConfig{ LogSpans: true, - LocalAgentHostPort: "jaeger:6831", + LocalAgentHostPort: jaeger_host_port, }, } @@ -65,7 +66,7 @@ func main() { opentracing.HTTPHeadersCarrier(r.Header), ) - span := tracer.StartSpan("/id GET", ext.RPCServerOption(spanCtx)) + span := tracer.StartSpan("videos-api: GET /id", ext.RPCServerOption(spanCtx)) defer span.Finish() if flaky == "true" { @@ -98,7 +99,7 @@ func main() { func video(writer http.ResponseWriter, request *http.Request, p httprouter.Params, ctx context.Context)(response string){ - span, _ := opentracing.StartSpanFromContext(ctx, "redis-get") + span, _ := opentracing.StartSpanFromContext(ctx, "videos-api: redis-get") defer span.Finish() id := p.ByName("id") diff --git a/tracing/docker-compose.yaml b/tracing/docker-compose.yaml index ebcf99c72..c768bbd60 100644 --- a/tracing/docker-compose.yaml +++ b/tracing/docker-compose.yaml @@ -18,6 +18,7 @@ services: - "ENVIRONMENT=DEBUG" - "REDIS_HOST=playlists-db" - "REDIS_PORT=6379" + - "JAEGER_HOST_PORT=jaeger:6831" ports: - 81:10010 networks: @@ -39,12 +40,32 @@ services: - "ENVIRONMENT=DEBUG" - "REDIS_HOST=videos-db" - "REDIS_PORT=6379" + - "JAEGER_HOST_PORT=jaeger:6831" #- "DELAY=true" #- "FLAKY=true" ports: - 82:10010 networks: - tracing + # videos-api-netcore: + # container_name: videos-api + # image: aimvector/jaeger-tracing:videos-api-netcore-1.0.0 + # build: + # context: ./applications-go/videos-api-netcore + # environment: + # - "ENVIRONMENT=DEBUG" + # - "REDIS_HOST=videos-db" + # - "REDIS_PORT=6379" + # - "JAEGER_AGENT_HOST=jaeger" + # - "JAEGER_AGENT_PORT=6831" + # - "JAEGER_SERVICE_NAME=videos-api" + # - "JAEGER_REPORTER_LOG_SPANS=true" + # - "JAEGER_SAMPLER_TYPE=const" + # - "JAEGER_PROPAGATION=jaeger" + # ports: + # - 82:5000 + # networks: + # - tracing videos-db: container_name: videos-db image: redis:6.0-alpine