コード例 #1
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            //Add CORS Policy
            services.AddCors(op =>
            {
                op.AddPolicy("AllowAll", policy =>
                {
                    policy.AllowAnyOrigin()
                    .AllowAnyHeader()
                    .AllowAnyMethod();
                });
            });

            services.AddSingleton <ITracer>(serviceProvider =>
            {
                ILoggerFactory loggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>();
                Jaeger.Configuration.SenderConfiguration.DefaultSenderResolver = new SenderResolver(loggerFactory).RegisterSenderFactory <ThriftSenderFactory>();

                var config     = Jaeger.Configuration.FromEnv(loggerFactory);
                ITracer tracer = config.GetTracer();
                GlobalTracer.Register(tracer);

                return(tracer);
            });

            services.AddOpenTracing();

            //Service bus configuration
            services.AddMassTransit(mt =>
            {
                mt.AddConsumer <OrderConsumer>();
                mt.AddBus(provider => Bus.Factory.CreateUsingRabbitMq(confg =>
                {
                    confg.UseHealthCheck(provider);
                    confg.Host(new Uri($"rabbitmq://{Configuration["RabbitMQHostName"]}"), host =>
                    {
                        host.Username("guest");
                        host.Password("guest");
                    });

                    confg.ReceiveEndpoint("ServiceResponseQueue", ep =>
                    {
                        ep.PrefetchCount = 16;
                        ep.ConfigureConsumer <OrderConsumer>(provider);
                    });
                }));
            });

            services.AddMassTransitHostedService();

            //Controller Addition
            services.AddControllers();

            //singleton to mimic memory
            AppMemory memory = new AppMemory();

            services.AddSingleton <AppMemory>(memory);

            //Service Discovery and Registry
            services.AddDiscoveryClient(Configuration);
            services.AddHealthChecks();
            services.AddSingleton <IHealthCheckHandler, ScopedEurekaHealthCheckHandler>();
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
        }
コード例 #2
0
 public void Registering_GlobalTracer_fails()
 {
     Assert.Throws <ArgumentException>(() => GlobalTracer.Register(GlobalTracer.Instance));
 }
コード例 #3
0
        static void Main(string[] args)
        {
            GlobalTracer.Register(new MockTracer());

            Abc(Environment.CurrentDirectory);
        }
コード例 #4
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            //services.AddDiscoveryClient(Configuration);

            services.Configure <ConsulConfig>(Configuration.GetSection("consulConfig"));

            services.AddSingleton <IConsulClient, ConsulClient>(p => new ConsulClient(consultConfig => {
                var address           = Configuration["consulConfig:address"];
                consultConfig.Address = new Uri(address);
            }));

            services.AddSingleton <IUnitOfWork>(option => new UnitOfWork(Configuration["connection_string"]));

            //var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration["token:key"]));
            //services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            //    .AddJwtBearer(options =>
            //    {
            //        options.TokenValidationParameters = new TokenValidationParameters
            //        {
            //            ValidateIssuer = true,
            //            ValidateAudience = true,
            //            ValidateLifetime = true,
            //            ValidateIssuerSigningKey = true,

            //            ValidIssuer = Configuration["token:issuer"],
            //            ValidAudience = Configuration["token:audience"],
            //            IssuerSigningKey = signingKey
            //        };
            //        options.Events = new JwtBearerEvents
            //        {
            //            OnAuthenticationFailed = context =>
            //            {
            //                Console.WriteLine("OnAuthenticationFailed" + context.Exception.Message);
            //                return Task.CompletedTask;
            //            },
            //            OnTokenValidated = context =>
            //            {
            //                Console.WriteLine("OnTokenValidated" + context.SecurityToken);
            //                return Task.CompletedTask;
            //            },
            //        };
            //    });

            services.AddSingleton <ITracer>(serviceProvider => {
                string serviceName = "SERVICE-REVERSE";

                ILoggerFactory loggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>();

                ISampler sampler = new ConstSampler(sample: true);

                ITracer tracer = new Tracer.Builder(serviceName)
                                 .WithLoggerFactory(loggerFactory)
                                 .WithSampler(sampler)
                                 .Build();

                GlobalTracer.Register(tracer);

                return(tracer);
            });

            services.AddOpenTracing();

            services.Configure <HttpHandlerDiagnosticOptions>(options =>
            {
                options.IgnorePatterns.Add(x => !x.RequestUri.IsLoopback);
            });

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }
コード例 #5
0
ファイル: Startup.cs プロジェクト: osstotalsoft/nbb
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo {
                    Title = "Contracts API", Version = "v1"
                });
            });

            services.AddSingleton(Configuration);
            services.TryAddSingleton <IHttpContextAccessor, HttpContextAccessor>();

            var transport = Configuration.GetValue("Messaging:Transport", "NATS");

            if (transport.Equals("NATS", StringComparison.InvariantCultureIgnoreCase))
            {
                services
                .AddMessageBus()
                .AddNatsTransport(Configuration)
                .UseTopicResolutionBackwardCompatibility(Configuration);
            }
            else if (transport.Equals("Rusi", StringComparison.InvariantCultureIgnoreCase))
            {
                services
                .AddMessageBus()
                .AddRusiTransport(Configuration)
                .UseTopicResolutionBackwardCompatibility(Configuration);
            }
            else
            {
                throw new Exception($"Messaging:Transport={transport} not supported");
            }

            services.AddContractsReadModelDataAccess();

            services.Decorate <IMessageBusPublisher, OpenTracingPublisherDecorator>();

            // OpenTracing
            services.AddOpenTracingCoreServices(builder => builder
                                                .AddAspNetCore()
                                                .AddHttpHandler()
                                                .AddGenericDiagnostics(x => x.IgnoredListenerNames.Add("Grpc.Net.Client"))
                                                .AddLoggerProvider()
                                                .AddMicrosoftSqlClient());

            services.AddSingleton <ITracer>(serviceProvider =>
            {
                if (!Configuration.GetValue <bool>("OpenTracing:Jaeger:IsEnabled"))
                {
                    return(NoopTracerFactory.Create());
                }

                string serviceName = Assembly.GetEntryAssembly().GetName().Name;

                ILoggerFactory loggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>();

                ITracer tracer = new Tracer.Builder(serviceName)
                                 .WithLoggerFactory(loggerFactory)
                                 .WithSampler(new ConstSampler(true))
                                 .WithReporter(new RemoteReporter.Builder()
                                               .WithSender(new HttpSender(Configuration.GetValue <string>("OpenTracing:Jaeger:CollectorUrl")))
                                               .Build())
                                 .Build();

                GlobalTracer.Register(tracer);

                return(tracer);
            });
        }
コード例 #6
0
ファイル: Program.cs プロジェクト: robswhitmore/hipster-shop
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine("Invalid number of arguments supplied");
                Environment.Exit(-1);
            }

            switch (args[0])
            {
            case "start":
                Parser.Default.ParseArguments <ServerOptions>(args).MapResult(
                    (ServerOptions options) =>
                {
                    Console.WriteLine($"Started as process with id {System.Diagnostics.Process.GetCurrentProcess().Id}");

                    // Set hostname/ip address
                    string hostname = options.Host;
                    if (string.IsNullOrEmpty(hostname))
                    {
                        Console.WriteLine($"Reading host address from {CART_SERVICE_ADDRESS} environment variable");
                        hostname = Environment.GetEnvironmentVariable(CART_SERVICE_ADDRESS);
                        if (string.IsNullOrEmpty(hostname))
                        {
                            Console.WriteLine($"Environment variable {CART_SERVICE_ADDRESS} was not set. Setting the host to 0.0.0.0");
                            hostname = "0.0.0.0";
                        }
                    }

                    // Set the port
                    int port = options.Port;
                    if (options.Port <= 0)
                    {
                        Console.WriteLine($"Reading cart service port from {CART_SERVICE_PORT} environment variable");
                        string portStr = Environment.GetEnvironmentVariable(CART_SERVICE_PORT);
                        if (string.IsNullOrEmpty(portStr))
                        {
                            Console.WriteLine($"{CART_SERVICE_PORT} environment variable was not set. Setting the port to 8080");
                            port = 8080;
                        }
                        else
                        {
                            port = int.Parse(portStr);
                        }
                    }

                    // Setup LightStep Tracer
                    Console.WriteLine($"Reading LightStep Access Token {ACCESS_TOKEN_ENV_VARIABLE} environment variable");
                    string accessToken = Environment.GetEnvironmentVariable(ACCESS_TOKEN_ENV_VARIABLE);

                    Datadog.Trace.Tracer.Instance.Settings.GlobalTags.Add("lightstep.service_name", "cartservice");
                    Datadog.Trace.Tracer.Instance.Settings.GlobalTags.Add("lightstep.access_token", accessToken);

                    var satelliteOptions = new SatelliteOptions(Environment.GetEnvironmentVariable("LIGHTSTEP_HOST"));
                    var overrideTags     = new Dictionary <string, object>
                    {
                        { LightStepConstants.ComponentNameKey, "cartservice" },
                        { "service.version", RedisCartStore.updateUserProfileValue ? RedisCartStore.UnhealthyVersion : RedisCartStore.HealthyVersion },
                        { "cartservice.identity", "f738e221f8" },
                        { "lightstep.hostname", "cartservice-0" },
                    };

                    var tracerOptions = new Options(accessToken).
                                        WithSatellite(satelliteOptions).
                                        WithTags(overrideTags);
                    var lightStepTracer = new LightStep.Tracer(
                        tracerOptions,
                        new LightStepSpanRecorder(),
                        new B3Propagator()
                        );

                    GlobalTracer.Register(lightStepTracer);

                    // Set redis cache host (hostname+port)
                    ICartStore cartStore;
                    string redis = ReadRedisAddress(options.Redis);

                    // Redis was specified via command line or environment variable
                    if (!string.IsNullOrEmpty(redis))
                    {
                        // If you want to start cart store using local cache in process, you can replace the following line with this:
                        // cartStore = new LocalCartStore();
                        cartStore = new RedisCartStore(redis);

                        return(StartServer(hostname, port, cartStore));
                    }
                    else
                    {
                        Console.WriteLine("Redis cache host(hostname+port) was not specified. Starting a cart service using local store");
                        Console.WriteLine("If you wanted to use Redis Cache as a backup store, you should provide its address via command line or REDIS_ADDRESS environment variable.");
                        cartStore = new LocalCartStore();
                    }

                    return(StartServer(hostname, port, cartStore));
                },
                    errs => 1);
                break;

            default:
                Console.WriteLine("Invalid command");
                break;
            }
        }
コード例 #7
0
 private static void ConnectTracing(TreeView tree)
 {
     GlobalTracer.Register(TreeViewTracer.Create(tree));
 }
コード例 #8
0
        public static void AddWorkerServices(this IServiceCollection services, IConfiguration configuration)
        {
            // MediatR
            services.AddMediatR(typeof(HelloWorld.Command).Assembly);
            services.Scan(scan => scan.FromAssemblyOf <HelloWorld.Handler>()
                          .AddClasses(classes => classes.AssignableTo(typeof(IPipelineBehavior <,>)))
                          .AsImplementedInterfaces()
                          .WithScopedLifetime());

            // Messaging
#if NatsMessagingTransport
            services.AddMessageBus().AddNatsTransport(configuration);
#endif
#if RusiMessagingTransport
            services.AddMessageBus().AddRusiTransport(configuration);
#endif

            services.Decorate <IMessageBusPublisher, SamplePublisherDecorator>();

#if OpenTracing
            services.Decorate <IMessageBusPublisher, OpenTracingPublisherDecorator>();
#endif
            services.AddMessagingHost(
                configuration,
                hostBuilder => hostBuilder
                .Configure(configBuilder => configBuilder
                           .AddSubscriberServices(selector =>
            {
                selector
                .FromMediatRHandledCommands()
                .AddAllClasses();
            })
                           .WithDefaultOptions()
                           .UsePipeline(pipelineBuilder => pipelineBuilder
                                        .UseCorrelationMiddleware()
                                        .UseExceptionHandlingMiddleware()
#if OpenTracing
                                        .UseMiddleware <OpenTracingMiddleware>()
#endif
#if Resiliency
                                        .UseDefaultResiliencyMiddleware()
#endif
                                        .UseMediatRMiddleware()
                                        .UseMiddleware <SampleSubscriberPipelineMiddleware>())));

#if OpenTracing
            // OpenTracing
            services.AddOpenTracing();

            services.AddSingleton <ITracer>(serviceProvider =>
            {
                if (!configuration.GetValue <bool>("OpenTracing:Jeager:IsEnabled"))
                {
                    return(NoopTracerFactory.Create());
                }

                string serviceName = Assembly.GetEntryAssembly().GetName().Name;

                ILoggerFactory loggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>();

                ITracer tracer = new Tracer.Builder(serviceName)
                                 .WithLoggerFactory(loggerFactory)
                                 .WithSampler(new ConstSampler(true))
                                 .WithReporter(new RemoteReporter.Builder()
                                               .WithSender(new UdpSender(
                                                               configuration.GetValue <string>("OpenTracing:Jeager:AgentHost"),
                                                               configuration.GetValue <int>("OpenTracing:Jeager:AgentPort"), 0))
                                               .Build())
                                 .Build();

                GlobalTracer.Register(tracer);

                return(tracer);
            });
#endif
        }
コード例 #9
0
        /// <summary>
        /// 添加Jaeger链路追踪,实例对象ITracer
        /// </summary>
        /// <param name="services"></param>
        /// <param name="openTracingBuilder"></param>
        /// <returns></returns>
        public static IServiceCollection AddJaeger(this IServiceCollection services, Action <IOpenTracingBuilder> openTracingBuilder = null)
        {
            if (openTracingBuilder == null)
            {
                openTracingBuilder = builder =>
                {
                    builder.AddCoreFx();
                    builder.AddAspNetCore();
                    builder.AddEntityFrameworkCore();
                    builder.AddLoggerProvider();
                    builder.ConfigureGenericDiagnostics(options =>
                    {
                    });
                    builder.ConfigureAspNetCore(options =>
                    {
                        options.Hosting.OperationNameResolver = (context) =>
                        {
                            return(context.Request.Path.ToUriComponent());
                        };
                        options.Hosting.IgnorePatterns.Add(a =>
                        {
                            return(false);
                        });
                    });
                };
            }

            services.AddOpenTracing(openTracingBuilder);
            services.AddSingleton(serviceProvider =>
            {
                var config              = serviceProvider.GetService <TracingConfiguration>();
                var serviceName         = config.SerivceName ?? serviceProvider.GetRequiredService <IHostingEnvironment>().ApplicationName;
                var loggerFactory       = serviceProvider.GetRequiredService <ILoggerFactory>();
                var endPoint            = config.EndPoint;
                var senderConfiguration = new Jaeger.Configuration.SenderConfiguration(loggerFactory);

                if (!string.IsNullOrEmpty(config.AgentHost))
                {
                    senderConfiguration
                    .WithAgentHost(config.AgentHost)
                    .WithAgentPort(config.AgentPort);
                }
                else
                {
                    senderConfiguration.WithEndpoint(endPoint);
                }


                var samplerConfiguration = new Jaeger.Configuration.SamplerConfiguration(loggerFactory)
                                           .WithType(config.SamplerType);

                var reporterConfiguration = new Jaeger.Configuration.ReporterConfiguration(loggerFactory)
                                            .WithFlushInterval(TimeSpan.FromSeconds(config.FlushIntervalSeconds))
                                            .WithLogSpans(config.LogSpans)
                                            .WithSender(senderConfiguration);


                OpenTracing.ITracer tracer = null;
                if (config.Open)
                {
                    tracer = new Jaeger.Configuration(serviceName, loggerFactory)
                             .WithSampler(samplerConfiguration)
                             .WithReporter(reporterConfiguration)
                             .GetTracer();
                }
                else
                {
                    tracer = new Jaeger.Tracer.Builder(serviceName)
                             .WithSampler(new Jaeger.Samplers.RateLimitingSampler(0))
                             .WithReporter(new Jaeger.Reporters.NoopReporter()).Build();
                }


                if (!GlobalTracer.IsRegistered())
                {
                    GlobalTracer.Register(tracer);
                }

                return(tracer);
            });
            return(services);
        }
コード例 #10
0
        public static void AddWorkerServices(this IServiceCollection services, IConfiguration configuration,
                                             bool useTestDoubles = false)
        {
#if MediatR
            // MediatR
            services.AddMediatR(typeof(__AHandler__).Assembly);
            services.AddScoped(typeof(IPipelineBehavior <,>), typeof(RequestPreProcessorBehavior <,>));
            services.AddScoped(typeof(IPipelineBehavior <,>), typeof(RequestPostProcessorBehavior <,>));
            services.Scan(scan => scan.FromAssemblyOf <__AHandler__>()
                          .AddClasses(classes => classes.AssignableTo(typeof(IPipelineBehavior <,>)))
                          .AsImplementedInterfaces()
                          .WithScopedLifetime());
#endif

            // Messaging
            if (useTestDoubles)
            {
                services.AddInProcessMessaging();
            }
            else
            {
#if NatsMessagingTransport
                services.AddNatsMessaging();
#elif KafkaMessagingTransport
                services.AddKafkaMessaging();
#endif
            }

#if (Resiliency)
            services.AddResiliency();
#endif
#if AddSamples
            services.Decorate <IMessageBusPublisher, SamplePublisherDecorator>();
#endif
#if OpenTracing
            services.Decorate <IMessageBusPublisher, OpenTracingPublisherDecorator>();
#endif
            services.AddMessagingHost()
            .AddSubscriberServices(selector =>
            {
#if MediatR
                selector
                .FromMediatRHandledCommands()
                .AddClassesAssignableTo <Command>();
#else
                selector
                .FromAssemblyOf <__ACommand__>()
                .AddClassesAssignableTo <Command>();
#endif
            })
            .WithDefaultOptions()
            .UsePipeline(builder => builder
                         .UseCorrelationMiddleware()
                         .UseExceptionHandlingMiddleware()
#if OpenTracing
                         .UseMiddleware <OpenTracingMiddleware>()
#endif
#if Resiliency
                         .UseDefaultResiliencyMiddleware()
#endif
#if MediatR
                         .UseMediatRMiddleware()
#endif
#if AddSamples
                         .UseMiddleware <SampleSubscriberPipelineMiddleware>()
#endif
                         );


#if FluentValidation
            // Validation
            services.Scan(scan => scan.FromAssemblyOf <__AValidator__>()
                          .AddClasses(classes => classes.AssignableTo <IValidator>())
                          .AsImplementedInterfaces()
                          .WithScopedLifetime());
#endif

#if AutoMapper
            // AutoMapper
            services.AddAutoMapper(typeof(__AMappingProfile__).Assembly);
#endif

#if OpenTracing
            // OpenTracing
            services.AddOpenTracing();

            services.AddSingleton <ITracer>(serviceProvider =>
            {
                if (!configuration.GetValue <bool>("OpenTracing:Jeager:IsEnabled"))
                {
                    return(NoopTracerFactory.Create());
                }

                string serviceName = Assembly.GetEntryAssembly().GetName().Name;

                ILoggerFactory loggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>();

                ITracer tracer = new Tracer.Builder(serviceName)
                                 .WithLoggerFactory(loggerFactory)
                                 .WithSampler(new ConstSampler(true))
                                 .WithReporter(new RemoteReporter.Builder()
                                               .WithSender(new UdpSender(
                                                               configuration.GetValue <string>("OpenTracing:Jeager:AgentHost"),
                                                               configuration.GetValue <int>("OpenTracing:Jeager:AgentPort"), 0))
                                               .Build())
                                 .Build();

                GlobalTracer.Register(tracer);

                return(tracer);
            });
#endif
        }
コード例 #11
0
        public static void EnableTracingForLegacyCode(
            LegacyFeaturesUsed flags,
            OutputSinks output)
        {
            if (flags.HasFlag(LegacyFeaturesUsed.CorrelationManager))
            {
                CorrelationManagerHook.PipeCorrelationManagerToOpenTracing();
            }

            var rawConsoleOut = Console.Out;

            if (flags.HasFlag(LegacyFeaturesUsed.ConsoleOut))
            {
                // Intercept Console.Out messages (this is a source)
                Console.SetOut(new OpenTracingTextWriter(
                                   // We do NOT set to Console.Out, so that we ensure all log messages go through us
                                   textWriterImplementation: TextWriter.Null));
            }

            // Start output
            if (output.HasFlag(OutputSinks.TraceSource))
            {
                // Create an ITracer/TraceSource pair for getting output FROM OpenTracing (this is a sink)
                var pair            = ToOpenTracing.OpenTracingTraceSource.CreateTracerTraceSourcePair();
                var traceSourceSink = pair.TraceSourceSink;
                var tracerSource    = pair.OpenTracingTracerSource;
                // Tell OT to write-to/actually-use that sink
                GlobalTracer.Register(tracerSource);

                OpenTracingTraceSource = traceSourceSink;
            }

            // Because it reads Trace.Listeners, must be before any writes to that.
            if (output.HasFlag(OutputSinks.CopyExistingTraceListeners))
            {
                if (!output.HasFlag(OutputSinks.TraceSource))
                {
                    throw new InvalidOperationException(
                              "Presently, you must pipe out to TraceSource to be able to get to Trace.Write, since that's all we've implemented.");
                }

                // No longer need to validate, since we write AFTER reading
                //if (flags.HasFlag(LegacyFeaturesUsed.TraceWrite))
                //{
                //    throw new InvalidOperationException(
                //        "Catching Trace.Write and piping output to Trace.Write would be cyclic");
                //}

                OpenTracingTraceSource.Listeners.AddRange(
                    Trace.Listeners);
            }

            if (flags.HasFlag(LegacyFeaturesUsed.TraceWrite))
            {
                OpenTracingTraceListener = new OpenTracingTraceListener();
                // Send Trace messages to OpenTracing (this is a source)
                Trace.Listeners.Add(OpenTracingTraceListener);
            }

            if (output.HasFlag(OutputSinks.ColoredConsole))
            {
                if (!output.HasFlag(OutputSinks.TraceSource))
                {
                    throw new InvalidOperationException(
                              "Presently, you must pipe out to TraceSource to be able to get to Console, since that's all we've implemented.");
                }

                var listener = new JsonDataConsoleTraceListener(rawConsoleOut);
                OpenTracingTraceSource.Listeners.Add(listener);
            }

            if (flags.HasFlag(LegacyFeaturesUsed.NoTracingSetup))
            {
                if (!flags.HasFlag(LegacyFeaturesUsed.ConsoleOut) &&
                    !flags.HasFlag(LegacyFeaturesUsed.TraceWrite))
                {
                    throw new ArgumentException(
                              "No need to set the NoTracingSetup flag if not using any features that will output to the active span.");
                }

                // Explicitly NOT disposing of the IScope, we want it to remain forever active
                var scope = GlobalTracer.Instance
                            .BuildSpan("GlobalSpan")
                            .StartActive();
            }
        }
コード例 #12
0
        // Registers and starts Jaeger.
        // Also registers OpenTracing related services!
        // Note: IHostEnvironment requires.NET Core 3.0. Either eliminate it if you don't need it, or use IHostingEnvironment
        // instead.
        public static IServiceCollection AddJaeger(this IServiceCollection services, IHostEnvironment env, string serviceName = null)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            services.AddSingleton <ITracer>(serviceProvider =>
            {
                // Two sensible alternatives
                serviceName ??= serviceProvider.GetRequiredService <IHostEnvironment>().ApplicationName;
                // serviceName ??= Assembly.GetEntryAssembly().GetName().Name;

                // This will be the service service name logged with the spans, displayed by Jaeger UI
                Environment.SetEnvironmentVariable("JAEGER_SERVICE_NAME", serviceName);

                // Based on env we can have different configuration for development and production environments
                if (env != null && env.IsDevelopment())
                {
                    // Check if we receive the specified env vars: if not, set defaults

                    var agentHost = Environment.GetEnvironmentVariable("JAEGER_AGENT_HOST"); // Host name for the jager agent
                    if (agentHost == null)
                    {
                        Environment.SetEnvironmentVariable("JAEGER_AGENT_HOST", "jaeger");
                    }

                    var agentPort = Environment.GetEnvironmentVariable("JAEGER_AGENT_PORT");
                    if (agentHost == null)
                    {
                        Environment.SetEnvironmentVariable("JAEGER_AGENT_PORT", "6831");
                    }

                    var sampler = Environment.GetEnvironmentVariable("JAEGER_SAMPLER_TYPE");
                    if (agentHost == null)
                    {
                        Environment.SetEnvironmentVariable("JAEGER_SAMPLER_TYPE", "const");
                    }
                }
                else
                {
                    // As for now do nothing, let's assume all environment variables are
                    // set properly in a production environment
                }

                // We could also create a new factory and configure it for our needs
                ILoggerFactory loggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>();

                // Get Jaeger config from environment
                var config = Jaeger.Configuration.FromEnv(loggerFactory);
                // We could further modify Jaeger config here
                var tracer = config.GetTracer();

                if (!GlobalTracer.IsRegistered())
                {
                    // Allows code that can't use DI to also access the tracer.
                    GlobalTracer.Register(tracer);
                }

                return(tracer);
            });

            // This has significance only when you send spans directly to the collector via HttpSender,
            // e.g. if JAEGER_ENDPOINT is specified. This is not the case in out setup, but keep it here.
            // Prevent endless loops when OpenTracing is tracking HTTP requests to Jaeger.
            // See https://github.com/jaegertracing/jaeger-client-csharp/issues/154
            //services.Configure<HttpHandlerDiagnosticOptions>(options =>
            //{
            //    // Update Url properly
            //    Uri _jaegerUri = new Uri("http://localhost:14268/api/traces");

            //    options.IgnorePatterns.Add(request => _jaegerUri.IsBaseOf(request.RequestUri));

            //    // This is not needed, just demonstrates some possibilities
            //    options.OnError = (span, exception, message) =>
            //    {

            //    };
            //    options.OnRequest = (span, request) =>
            //    {

            //    };
            //});

            // Also add Open Tracing related services
            services.AddOpenTracing();

            return(services);
        }
コード例 #13
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Use "OpenTracing.Contrib.NetCore" to automatically generate spans for ASP.NET Core
            services.AddSingleton <ITracer>(serviceProvider =>
            {
                ILoggerFactory loggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>();
                // use the environment variables to setup the Jaeger endpoints
                var config = Jaeger.Configuration.FromEnv(loggerFactory);
                var tracer = config.GetTracer();

                GlobalTracer.Register(tracer);

                return(tracer);
            });
            services.AddOpenTracing();

            // Register the Swagger generator, defining one or more Swagger documents
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo {
                    Title       = "OpenRMF Controls API", Version = "v1",
                    Description = "The Controls API that goes with the OpenRMF tool",
                    Contact     = new OpenApiContact
                    {
                        Name  = "Dale Bingham",
                        Email = "*****@*****.**",
                        Url   = new Uri("https://github.com/Cingulara/openrmf-api-controls")
                    }
                });
            });

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(o =>
            {
                o.Authority                 = Environment.GetEnvironmentVariable("JWT-AUTHORITY");
                o.Audience                  = Environment.GetEnvironmentVariable("JWT-CLIENT");
                o.IncludeErrorDetails       = true;
                o.RequireHttpsMetadata      = false;
                o.TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidateAudience         = false,
                    ValidateIssuerSigningKey = true,
                    ValidateIssuer           = true,
                    ValidIssuer      = Environment.GetEnvironmentVariable("JWT-AUTHORITY"),
                    ValidateLifetime = true
                };

                o.Events = new JwtBearerEvents()
                {
                    OnAuthenticationFailed = c =>
                    {
                        c.NoResult();
                        c.Response.StatusCode  = 401;
                        c.Response.ContentType = "text/plain";

                        return(c.Response.WriteAsync(c.Exception.ToString()));
                    }
                };
            });

            // setup the RBAC for this
            services.AddAuthorization(options =>
            {
                options.AddPolicy("Administrator", policy => policy.RequireRole("roles", "[Administrator]"));
                options.AddPolicy("Editor", policy => policy.RequireRole("roles", "[Editor]"));
                options.AddPolicy("Reader", policy => policy.RequireRole("roles", "[Reader]"));
                options.AddPolicy("Assessor", policy => policy.RequireRole("roles", "[Assessor]"));
            });

            // add the CORS setup
            services.AddCors(options =>
            {
                options.AddPolicy(name: MyAllowSpecificOrigins,
                                  builder =>
                {
                    builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin();
                });
            });

            // add service for allowing caching of responses
            services.AddResponseCaching();

            services.AddControllers();
        }
コード例 #14
0
 public void Registering_null_fails()
 {
     Assert.Throws <ArgumentNullException>(() => GlobalTracer.Register(null));
 }
コード例 #15
0
ファイル: Program.cs プロジェクト: Ciorna/PSSC-2020
        static void Main(string[] args)
        {
            new HostBuilder()
            .ConfigureServices(services =>
            {
                services.AddSingleton <ITracer>(sp =>
                {
                    string serviceName           = Assembly.GetEntryAssembly().GetName().Name;
                    ILoggerFactory loggerFactory = sp.GetRequiredService <ILoggerFactory>();
                    ISampler sampler             = new ConstSampler(true);

                    var telemetryConfig =
                        new TelemetryConfiguration("eb9eab65-f8b2-4af5-9c4c-1fc7912b8ac3");
                    var builder = telemetryConfig.TelemetryProcessorChainBuilder;
                    builder.Use((next) => new AppinsightsOpenTracingInterceptor(next));
                    builder.Build();

                    //ApplicationInsightsTracer tracer =
                    //    new ApplicationInsightsTracer(telemetryConfig);

                    ITracer tracer = new Tracer.Builder(serviceName)
                                     .WithLoggerFactory(loggerFactory)
                                     .WithSampler(sampler)
                                     .Build();

                    GlobalTracer.Register(tracer);
                    return(tracer);
                });
                services.AddOpenTracing();
            }).Build().Start();

            var host = new SiloHostBuilder()
                       .UseLocalhostClustering()
                       .ConfigureEndpoints(IPAddress.Parse("127.0.0.1"), 11111, 30000)
                       .ConfigureApplicationParts(parts =>
            {
                parts.AddApplicationPart(typeof(EndToEndScenarioGrain).Assembly).WithReferences()
                .WithCodeGeneration();
                parts.AddApplicationPart(typeof(BackofficeGrain).Assembly).WithReferences().WithCodeGeneration();
            })
                       .AddRedisStreams("RedisProvider", // Add the Redis stream provider
                                        c => c.ConfigureRedis(options => options.ConnectionString = "localhost"))
                       .AddMemoryGrainStorage("PubSubStore")
                       .AddIncomingGrainCallFilter <StreamInterceptor>()
                       .ConfigureServices(services =>
            {
                services.AddHttpClient("ref", client =>
                {
                    client.BaseAddress = new Uri("http://localhost:5000/graphql");
                });
                services.AddSingleton <Func <GraphQLHttpClient> >((sp) => () =>
                                                                  new GraphQLHttpClient(new GraphQLHttpClientOptions(), new SystemTextJsonSerializer(),
                                                                                        sp.GetRequiredService <IHttpClientFactory>().CreateClient("ref")));
            })

                       /*.ConfigureLogging(builder => {
                        *  builder.AddConsole();
                        * })*/
                       .AddStartupTask <StartupTask>()
                       .Build();

            host.StartAsync().Wait();
            Console.ReadLine();
        }
コード例 #16
0
 public void Registering_NoopTracer_indicates_tracer_has_been_registered()
 {
     Assert.False(GlobalTracer.IsRegistered());
     GlobalTracer.Register(NoopTracerFactory.Create());
     Assert.True(GlobalTracer.IsRegistered());
 }
コード例 #17
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            // Redis database service
            if (Environment.GetEnvironmentVariable("RedisAddress") == null)
            {
                Environment.SetEnvironmentVariable("RedisAddress", "127.0.0.1:6379");
            }
            if (Environment.GetEnvironmentVariable("RedisPassword") == null)
            {
                Environment.SetEnvironmentVariable("RedisPassword", "");
            }
            if (Environment.GetEnvironmentVariable("DatabaseName") == null)
            {
                Environment.SetEnvironmentVariable("DatabaseName", "1");
            }
            services.AddSingleton <IRedisDatabaseProvider, RedisDatabaseProvider>();

            // Swagger
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo {
                    Title = "Book Stocks API", Version = "v1"
                });
            });

            //HealthChecks
            services.AddHealthChecks()
            .AddRedis(redisConnectionString: Environment.GetEnvironmentVariable("RedisAddress") +
                      ",defaultDatabase=" + Environment.GetEnvironmentVariable("DatabaseName") +
                      ",password="******"RedisPassword"),
                      failureStatus: HealthStatus.Degraded,
                      tags: new[] { Readiness });

            // OpenTracing
            services.AddOpenTracing();

            // Adds the Jaeger Tracer.
            services.AddSingleton <ITracer>(serviceProvider =>
            {
                string serviceName = serviceProvider.GetRequiredService <Microsoft.AspNetCore.Hosting.IWebHostEnvironment>().ApplicationName;

                if (Environment.GetEnvironmentVariable("JAEGER_SERVICE_NAME") == null)
                {
                    Environment.SetEnvironmentVariable("JAEGER_SERVICE_NAME", serviceName);
                }
                if (Environment.GetEnvironmentVariable("JAEGER_AGENT_HOST") == null)
                {
                    Environment.SetEnvironmentVariable("JAEGER_AGENT_HOST", "localhost");
                }
                if (Environment.GetEnvironmentVariable("JAEGER_AGENT_PORT") == null)
                {
                    Environment.SetEnvironmentVariable("JAEGER_AGENT_PORT", "6831");
                }
                if (Environment.GetEnvironmentVariable("JAEGER_SAMPLER_TYPE") == null)
                {
                    Environment.SetEnvironmentVariable("JAEGER_SAMPLER_TYPE", "const");
                }

                var loggerFactory = new LoggerFactory();

                var config = Jaeger.Configuration.FromEnv(loggerFactory);
                var tracer = config.GetTracer();

                if (!GlobalTracer.IsRegistered())
                {
                    // Allows code that can't use DI to also access the tracer.
                    GlobalTracer.Register(tracer);
                }

                return(tracer);
            });
        }
コード例 #18
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(o => o.AddPolicy(Constants.CORS_POLICY, builder =>
            {
                builder.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader();
            }));
            services.Configure <FormOptions>(x =>
            {
                x.MultipartBodyLengthLimit = long.MaxValue;
            });
            services.AddMvc()
            .AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
                options.JsonSerializerOptions.IgnoreNullValues = true;
            });
            services.ConfigureServices(Configuration);
            services.AddTransient <IFileUtility, FileUtility>();
            services.AddTransient <IZipUtility, ZipUtility>();
            services.AddControllers();
            services.AddOpenTracing();
            services.AddSwaggerGen(c =>
            {
                c.DocumentFilter <CloudSDKDocumentFilter>();
            });

            // Adds the Jaeger Tracer.
            services.AddSingleton <ITracer>(serviceProvider =>
            {
                string serviceName = serviceProvider.GetRequiredService <IHostEnvironment>().ApplicationName;

                //string serviceName = System.Reflection.Assembly.GetEntryAssembly().GetName().Name;

                ILoggerFactory loggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>();

                Jaeger.Samplers.ISampler sampler = new Jaeger.Samplers.ConstSampler(sample: true);

                // This will log to a default localhost installation of Jaeger.
                Tracer tracer = new Tracer.Builder(serviceName)
                                .WithLoggerFactory(loggerFactory)
                                .WithSampler(new Jaeger.Samplers.ConstSampler(true))
                                .Build();

                //Environment.SetEnvironmentVariable("JAEGER_SERVICE_NAME", "rebuild-rest-api");
                //Environment.SetEnvironmentVariable("JAEGER_AGENT_HOST", "simplest-agent.observability.svc.cluster.local");
                //Environment.SetEnvironmentVariable("JAEGER_AGENT_PORT", "6831");
                //Environment.SetEnvironmentVariable("JAEGER_SAMPLER_TYPE", "const");

                //LoggerFactory loggerFactory = new LoggerFactory();

                //Configuration config = Jaeger.Configuration.FromEnv(loggerFactory);
                //ITracer tracer = config.GetTracer();

                if (!GlobalTracer.IsRegistered())
                {
                    // Allows code that can't use DI to also access the tracer.
                    GlobalTracer.Register(tracer);
                }

                return(tracer);
            });
        }
コード例 #19
0
        public static async Task Main(string[] args)
        {
            var builder = Host
                          .CreateDefaultBuilder(args)
                          .ConfigureLogging((hostingContext, loggingBuilder) =>
            {
                var env = hostingContext.HostingEnvironment.IsDevelopment();
                var connectionString = hostingContext.Configuration.GetConnectionString("Logs");

                Log.Logger = new LoggerConfiguration()
                             .MinimumLevel.Debug()
                             .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
                             .Enrich.FromLogContext()
                             .Enrich.With <CorrelationLogEventEnricher>()
                             .WriteTo.MSSqlServer(connectionString,
                                                  new MSSqlServerSinkOptions {
                    TableName = "Logs", AutoCreateSqlTable = true
                })
                             .CreateLogger();

                loggingBuilder.AddSerilog(dispose: true);
                loggingBuilder.AddFilter("Microsoft", logLevel => logLevel >= LogLevel.Warning);
                loggingBuilder.AddConsole();
            })
                          .ConfigureServices((hostingContext, services) =>
            {
                services.AddMediatR(typeof(ContractCommandHandlers).Assembly);


                var transport = hostingContext.Configuration.GetValue("Messaging:Transport", "NATS");
                if (transport.Equals("NATS", StringComparison.InvariantCultureIgnoreCase))
                {
                    services
                    .AddMessageBus()
                    .AddNatsTransport(hostingContext.Configuration)
                    .UseTopicResolutionBackwardCompatibility(hostingContext.Configuration);
                }
                else if (transport.Equals("Rusi", StringComparison.InvariantCultureIgnoreCase))
                {
                    services
                    .AddMessageBus()
                    .AddRusiTransport(hostingContext.Configuration)
                    .UseTopicResolutionBackwardCompatibility(hostingContext.Configuration);
                }
                else
                {
                    throw new Exception($"Messaging:Transport={transport} not supported");
                }

                services.AddContractsWriteModelDataAccess();
                services.AddContractsReadModelDataAccess();


                services.AddEventStore()
                .WithNewtownsoftJsonEventStoreSeserializer(new[] { new SingleValueObjectConverter() })
                .WithAdoNetEventRepository();

                services.Decorate <IMessageBusPublisher, OpenTracingPublisherDecorator>();
                services.AddMessagingHost(hostingContext.Configuration, hostBuilder => hostBuilder.UseStartup <MessagingHostStartup>());

                // OpenTracing
                services.AddOpenTracingCoreServices(builder => builder.AddGenericDiagnostics().AddMicrosoftSqlClient());


                services.AddSingleton <ITracer>(serviceProvider =>
                {
                    if (!hostingContext.Configuration.GetValue <bool>("OpenTracing:Jaeger:IsEnabled"))
                    {
                        return(NoopTracerFactory.Create());
                    }

                    string serviceName = Assembly.GetEntryAssembly().GetName().Name;

                    ILoggerFactory loggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>();

                    ITracer tracer = new Tracer.Builder(serviceName)
                                     .WithLoggerFactory(loggerFactory)
                                     .WithSampler(new ConstSampler(true))
                                     .WithReporter(new RemoteReporter.Builder()
                                                   .WithSender(new HttpSender(hostingContext.Configuration.GetValue <string>("OpenTracing:Jaeger:CollectorUrl")))
                                                   .Build())
                                     .Build();

                    GlobalTracer.Register(tracer);

                    return(tracer);
                });
            });

            var host = builder.Build();

            await host.RunAsync();
        }
コード例 #20
0
        static async Task Main(string[] args)
        {
            var serviceName = "DrawNiceTrace" + Guid.NewGuid();
            var tracer      = new Tracer.Builder(serviceName)
                              .WithSampler(new ConstSampler(true))
                              .Build();

            GlobalTracer.Register(tracer);

            var rootContext = new RootContext(new MessageHeader(), OpenTracingExtensions.OpenTracingSenderMiddleware())
                              .WithOpenTracing();

            var bankProps = Props.FromFunc(async ctx =>
            {
                switch (ctx.Message)
                {
                case ProcessPayment _:
                    ctx.Respond(new ProcessPaymentResponse {
                        Ok = true
                    });
                    break;
                }
            }).WithOpenTracing();
            var bank = rootContext.Spawn(bankProps);


            var restaurantProps = Props.FromFunc(async ctx =>
            {
                switch (ctx.Message)
                {
                case TriggerFood trigger:
                    using (GlobalTracer.Instance.BuildSpan("Preparing food !").StartActive())
                    {
                        await Task.Delay(1000);
                    }
                    ctx.Send(trigger.Customer, new DeliverFood());
                    break;
                }
            }).WithOpenTracing();
            var restaurant = rootContext.Spawn(restaurantProps);


            var  cartProps      = Props.FromProducer(() => new CartActor(bank)).WithOpenTracing();
            long nextCartNumber = 1;

            string getActorName(long number) => $"cart-{number}";

            var dinnerProps = Props.FromFunc(async ctx =>
            {
                switch (ctx.Message)
                {
                case AddItem addItem:
                    PID cartPID;
                    if (addItem.CartNumber == default)
                    {
                        var cartNumber = nextCartNumber++;
                        cartPID        = ctx.SpawnNamed(cartProps, getActorName(cartNumber));
                        ctx.Send(cartPID, new AssignCartNumber {
                            CartNumber = cartNumber
                        });
                    }
                    else
                    {
                        var cartActorName = getActorName(addItem.CartNumber);
                        cartPID           = ctx.Children.First(p => p.Id.EndsWith(cartActorName));
                    }
                    ctx.Forward(cartPID);
                    break;

                case ConfirmOrder confirmOrder:
                    var orderPid = ctx.Children.First(p => p.Id.EndsWith(getActorName(confirmOrder.CartNumber)));
                    ctx.Forward(orderPid);
                    break;

                case SendPaymentDetails sendPaymentDetails:
                    var orderPid2 = ctx.Children.First(p => p.Id.EndsWith(getActorName(sendPaymentDetails.OrderNumber)));
                    var resp      = await ctx.RequestAsync <ProcessPaymentResponse>(orderPid2, sendPaymentDetails);
                    if (resp.Ok)     // it will always, we have super rich customers
                    {
                        ctx.Send(restaurant, new TriggerFood {
                            Customer = sendPaymentDetails.Customer, OrderNumber = sendPaymentDetails.OrderNumber
                        });
                    }
                    break;
                }
            }).WithOpenTracing();
            var dinner = rootContext.Spawn(dinnerProps);


            var customerProps = Props.FromFunc(async ctx =>
            {
                switch (ctx.Message)
                {
                case Started _:
                    var cartNumberResponse = await ctx.RequestAsync <CartNumberResponse>(dinner, new AddItem {
                        ProductName = "Beer!"
                    });
                    var cartNumber = cartNumberResponse.CartNumber;

                    await Task.Delay(100);
                    await ctx.RequestAsync <CartNumberResponse>(dinner, new AddItem {
                        CartNumber = cartNumber, ProductName = "Pizza."
                    });
                    await Task.Delay(100);
                    await ctx.RequestAsync <CartNumberResponse>(dinner, new AddItem {
                        CartNumber = cartNumber, ProductName = "Ice cream."
                    });

                    await Task.Delay(200);
                    var confirmed = await ctx.RequestAsync <ConfirmOrderResponse>(dinner, new ConfirmOrder {
                        CartNumber = cartNumber
                    });

                    await Task.Delay(300);
                    ctx.Send(dinner, new SendPaymentDetails {
                        Customer = ctx.Self, OrderNumber = confirmed.OrderNumber
                    });

                    break;

                case DeliverFood deliver:
                    throw new Exception("Food Delivered !");
                }
            })
                                .WithOpenTracing()
                                .WithGuardianSupervisorStrategy(new OneForOneStrategy((pid, reason) => SupervisorDirective.Stop, 0, null));

            rootContext.Spawn(customerProps);

            await Task.Delay(TimeSpan.FromSeconds(10));

            Console.WriteLine("Done! Go to jaeger : http://localhost:16686/search?service=" + serviceName);
            Console.WriteLine("Press [Enter]");
            Console.ReadLine();
        }
コード例 #21
0
        public void ConfigureServices(IServiceCollection services)
        {
            ConfigureConsul(services);
            services.AddSingleton <ITracer>(serviceProvider =>
            {
                string serviceName = Assembly.GetEntryAssembly().GetName().Name;

                ILoggerFactory loggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>();

                ISampler sampler = new ConstSampler(sample: true);

                ITracer tracer = new Tracer.Builder(serviceName)
                                 .WithLoggerFactory(loggerFactory)
                                 .WithSampler(sampler)
                                 .Build();

                GlobalTracer.Register(tracer);

                return(tracer);
            });

            // services.AddOpenTracing();

            // services.AddMvc()
            services.AddMvcCore()
            .AddAuthorization()
            .AddJsonFormatters(options =>
                               options.ContractResolver = new CamelCasePropertyNamesContractResolver())
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            var connString = Configuration["ConnectionStrings:Default"];

            services.AddDbContext <ApplicationDBContext>(o => o.UseSqlServer(connString));
            services.AddIdentity <IdentityUser, IdentityRole>()
            .AddDefaultTokenProviders()
            .AddEntityFrameworkStores <ApplicationDBContext>();

            services.Configure <IdentityOptions>(options => {
                options.Password.RequiredLength         = 3;
                options.Password.RequireDigit           = true;
                options.Password.RequireNonAlphanumeric = false;
                options.Lockout.MaxFailedAccessAttempts = Convert.ToInt32(Configuration["User:MaxFailedAccessAttempts"]);
                options.Lockout.DefaultLockoutTimeSpan  = TimeSpan.FromMinutes(Convert.ToDouble(Configuration["User:LockoutTime"]));
                options.SignIn.RequireConfirmedEmail    = Convert.ToBoolean(Configuration["User:RequireConfirmedEmail"]);
            });

            services.ConfigureApplicationCookie(option => {
                option.LoginPath        = "/Identity/Signin";
                option.AccessDeniedPath = "/Identity/AccessDenied";
                option.ExpireTimeSpan   = TimeSpan.FromHours(10);
            });

            services.AddAuthorization(option => {
                option.AddPolicy("MemberDep", p => {
                    p.RequireClaim("Department", "Tech", "Full Stack").RequireRole("User");
                });

                option.AddPolicy("AdminDep", p => {
                    p.RequireClaim("Department", "Tech", "hr").RequireRole("Admin");
                });
            });
        }