How can I send traces to Jaeger from C#? - c#

I'm trying to use the Jaeger package to send traces to Jaeger from a C# app.
There are no minimal examples in the jaeger-client-csharp documentation, but from what I read, I think this should work.
using Jaeger;
using Jaeger.Samplers;
namespace jaegertest
{
class Program
{
static void Main(string[] args)
{
var tracer = new Tracer.Builder("my-service")
.WithSampler(new ConstSampler(true))
.Build();
using (var scope = tracer.BuildSpan("foo").StartActive(true))
{
System.Threading.Thread.Sleep(1000);
}
}
}
}
I have jaeger-all-in-one.exe running but when I run this code there's no sign of any new traces. I've tried manually configuring samplers, senders, reporters, etc. but nothing I tried worked. What do I need to add to get my traces to appear in Jaeger?

This is the simplest working example that I was able to find.
using Jaeger;
using Jaeger.Reporters;
using Jaeger.Samplers;
using Jaeger.Senders.Thrift;
namespace jaegertest
{
class Program
{
static void Main(string[] args)
{
var tracer = new Tracer.Builder("my-service")
.WithSampler(new ConstSampler(true))
.WithReporter(new RemoteReporter.Builder()
.WithSender(new UdpSender())
.Build())
.Build();
using (var scope = tracer.BuildSpan("foo").StartActive(true))
{
System.Threading.Thread.Sleep(1000);
}
tracer.Dispose();
}
}
}
Here is a more realistic example that builds the tracer from a configuration.
using Jaeger;
using Jaeger.Samplers;
using Jaeger.Senders;
using Jaeger.Senders.Thrift;
using Microsoft.Extensions.Logging;
namespace jaegertest
{
class Program
{
static void Main(string[] args)
{
var loggerFactory = new LoggerFactory();
var samplerConfiguration = new Configuration.SamplerConfiguration(loggerFactory)
.WithType(ConstSampler.Type)
.WithParam(1);
var senderResolver = new SenderResolver(loggerFactory)
.RegisterSenderFactory<ThriftSenderFactory>();
var senderConfiguration = new Configuration.SenderConfiguration(loggerFactory)
.WithSenderResolver(senderResolver);
var reporterConfiguration = new Configuration.ReporterConfiguration(loggerFactory)
.WithSender(senderConfiguration)
.WithLogSpans(true);
var tracer = (Tracer)new Configuration("my-service", loggerFactory)
.WithSampler(samplerConfiguration)
.WithReporter(reporterConfiguration)
.GetTracer();
using (var scope = tracer.BuildSpan("foo").StartActive(true))
{
System.Threading.Thread.Sleep(1000);
}
tracer.Dispose();
}
}
}

Related

How to make MSTest grab all console output from unit test? Output behind WebHost.CreateDefaultBuilder() goes missing (VS2022, .NET 6, MSTest 2.2.10)

I'm creating an integration test for a Web API, so I'm starting an entire application in a unit test using WebHost.CreateDefaultBuilder() and the usual setup bits.
While unit testing, my log framework writes to console to ease debugging of failing tests. However, console writing from within the application does not work. I see log before and after from the parts of the test that is not within the app. Currently I have to get around the issue by logging to file, but would be really nice if there was a way for console output to work.
Sadly with the nature of the integration test, a minimal reproduction isn't that minimal, but this reproduce the issue in 2 cases, and shows a working but very tedious workaround.
Project file with deps:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>10.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.24" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
</ItemGroup>
</Project>
And the actual test implementation:
namespace Reproduce.Tests
{
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
[TestClass]
public class ReproduceConsoleOutIssueTest
{
// A log class that logs through given LogAction if given, or directly on Console if not.
public class Logger
{
internal readonly List<string> RecordedLog = new();
internal Action<string> LogAction { get; set; }
internal void Log(string msg)
{
RecordedLog.Add(msg);
var action = LogAction ?? Console.Out.WriteLine;
action("INTERNAL LOGGING " + msg);
}
}
// A simple controller that tries to log
public class MyController : ControllerBase
{
private readonly Logger _log;
public MyController(Logger log) { _log = log; }
[Route("api/test"), HttpGet]
public string Test()
{
_log.Log("Test was called");
return "Yay";
}
}
internal class Startup
{
private class ControllerSelector : IApplicationFeatureProvider<ControllerFeature>
{
internal ICollection<TypeInfo> Controllers { get; init; }
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
{
foreach (var c in Controllers) feature.Controllers.Add(c);
}
}
public void ConfigureServices(IServiceCollection services)
{
var mvcCoreBuilder = services.AddMvcCore();
mvcCoreBuilder.ConfigureApplicationPartManager(apm => apm.FeatureProviders.Add(
new ControllerSelector { Controllers = new[] { typeof(MyController).GetTypeInfo() }}
));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(e => { e.MapControllers(); });
}
}
[TestMethod]
public async Task ReproduceIssueWhenDirectConsoleWriting()
{
// This use Console.Out.WriteLine that doesn't show the log from within controller.
var logger = new Logger();
await TryToReproduceIssueWithGivenLoggerAsync(logger);
}
[TestMethod]
public async Task ReproduceIssueWhenLoggingThroughAction()
{
// Attempt to use func to run in console configured outside app but didn't help any.
var logger = new Logger { LogAction = m => Console.WriteLine(m) };
await TryToReproduceIssueWithGivenLoggerAsync(logger);
}
[TestMethod]
public async Task WorksOnTediousContextChange()
{
// But if we just grab the state and log in a task/thread outside app context it works.
var myLog = new Queue<string>();
var logSent = new SemaphoreSlim(0);
var logWritten = new SemaphoreSlim(0);
var logWriterToken = new CancellationTokenSource();
var logWriter = Task.Run(async () =>
{
while (!logWriterToken.IsCancellationRequested)
{
try
{
await logSent.WaitAsync(logWriterToken.Token);
}
catch (OperationCanceledException)
{
break;
}
Console.WriteLine(myLog.Dequeue());
logWritten.Release();
}
});
var logger = new Logger
{
LogAction = m =>
{
myLog.Enqueue(m);
logSent.Release();
logWritten.Wait();
}
};
await TryToReproduceIssueWithGivenLoggerAsync(logger);
logWriterToken.Cancel();
await logWriter;
}
private async Task TryToReproduceIssueWithGivenLoggerAsync(Logger logger)
{
logger.Log("Starting");
using var webHost = WebHost.CreateDefaultBuilder()
.ConfigureServices(s =>
{
s.AddSingleton(this);
s.AddSingleton(logger);
}).UseStartup<Startup>()
.Build();
var ctoken = new CancellationTokenSource();
await webHost.StartAsync(ctoken.Token);
var addr = webHost.ServerFeatures.Get<IServerAddressesFeature>()?.Addresses.First();
var port = int.Parse(addr.Substring(addr.LastIndexOf(':') + 1));
Assert.IsTrue(port >= 1024 && port <= 65536);
using (var httpClient = new HttpClient())
{
var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, new Uri($"http://localhost:{port}/api/test")));
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
Assert.AreEqual("Yay", content);
}
ctoken.Cancel();
await webHost.StopAsync(CancellationToken.None);
logger.Log("Done");
Assert.AreEqual("Starting, Test was called, Done", string.Join(", ", logger.RecordedLog));
}
}
}

Async API Request New

I am trying to make an API call in an ASP.NET web form. The request works fine in Console, but async requests are timing out and not working. Please advise.
Console App Code:
using System;
using System.Collections.Generic;
using System.Text;
using Newegg.Marketplace.SDK;
using Newegg.Marketplace.SDK.Base;
using Newegg.Marketplace.SDK.DataFeed;
using Newegg.Marketplace.SDK.DataFeed.Model;
using Newegg.Marketplace.SDK.Item;
using Newegg.Marketplace.SDK.Item.Model;
using Newegg.Marketplace.SDK.Order;
using Newegg.Marketplace.SDK.Order.Model;
using Newegg.Marketplace.SDK.Other;
using Newegg.Marketplace.SDK.Other.Model;
using Newegg.Marketplace.SDK.Report.Model;
using Newegg.Marketplace.SDK.RMA;
using Newegg.Marketplace.SDK.RMA.Model;
using Newegg.Marketplace.SDK.Seller;
using Newegg.Marketplace.SDK.Seller.Model;
using Newegg.Marketplace.SDK.Shipping.Model;
namespace example
{
public class Demo
{
private OrderCall ordercall;
private ItemCall itemCall;
private SellerCall sellerCall;
private DatafeedCall datafeedCall;
private RMACall rmaCall;
private ShippingCall shippingCall;
private ReportCall reportCall;
private OtherCall otherCall;
public Demo()
{
//Construct an APIConfig with SellerID, APIKey(Authorization) and SecretKey.
APIConfig config = new APIConfig("****", "********************************", "********-****-****-****-************");
// or load the config file to get it.
//APIConfig config = APIConfig.FromJsonFile("setting.json");
//Create a APIClient with the config
APIClient client = new APIClient(config);
//Create the Api Call object with he client.
ordercall = new OrderCall(client);
itemCall = new ItemCall(client);
sellerCall = new SellerCall(client);
datafeedCall = new DatafeedCall(client);
rmaCall = new RMACall(client);
shippingCall = new ShippingCall(client);
reportCall = new ReportCall(client);
otherCall = new OtherCall(client);
}
public void GetOrderStatus()
{
Console.WriteLine("GetOrderStatus");
// Send your request and get response
var orderstatus = ordercall.GetOrderStatus("105137040").Result;
// Use the data pre you business
Console.WriteLine(string.Format("There order status is {0}.", orderstatus.OrderStatusName));
}
}
My ASP.NET code
public partial class HomePage : System.Web.UI.Page
{
private OrderCall orderCall;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
RegisterAsyncTask(new PageAsyncTask(LoadSomeData));
}
}
public async Task LoadSomeData()
{
string path = #"C:\Users\*****\source\repos\Orders\Settings\setting.json";
APIConfig config = APIConfig.FromJsonFile(path);
APIClient client = new APIClient(config);
orderCall = new OrderCall(client);
try
{
var orderstatus = await orderCall.GetOrderStatus("105137040");
Debug.Write(orderstatus.OrderStatusName);
Connect.BackColor = Color.Green;
}
catch (Exception ex)
{
Connect.BackColor = Color.Red;
Debug.WriteLine(ex.Message);
}
}
}
}
After using my code, the page freezes and eventually times out. The returned object is also null or returns an error.

Couchbase Lite 2.1 Replicator Issue .net

We have just upgraded our SyncGatewaty to 2.1. So now I’m refactoring our client code to use CouchbaseLite 2.1. When I try to replicate I get the error:
Got LiteCore error: Not Found (6/404)
I originally got the error when connecting to our Dev Server, and then installed a local clean copy on my laptop and I get the same error when trying to connect to it too.
Log:
INFO) Couchbase 2019-01-10T10:56:47.8503147-07:00 (Startup) [1] CouchbaseLite/2.1.2 (.NET; Microsoft Windows 10.0.17763 ) Build/13 LiteCore/ (15) Commit/9aebf28
WARNING) LiteCore 2019-01-10T10:56:48.1943139-07:00 {C4SocketImpl#1}==> class litecore::repl::C4SocketImpl ws://localhost.com:443//_blipsync
WARNING) LiteCore 2019-01-10T10:56:48.1943139-07:00 {C4SocketImpl#1} Unexpected or unclean socket disconnect! (reason=WebSocket status, code=404)
ERROR) Sync 2019-01-10T10:56:48.1993137-07:00 {Repl#2}==> class litecore::repl::Replicator c:\temp\content_meta_data.cblite2\ ->ws://localhost:443//_blipsync
ERROR) Sync 2019-01-10T10:56:48.1993137-0
7:00 {Repl#2} Got LiteCore error: Not Found (6/404)
My code:
using System;
using System.IO;
using Couchbase.Lite;
using Couchbase.Lite.Support;
using Couchbase.Lite.Sync;
using NLog;
namespace ReplicatorExample
{
public class DatabaseManager
{
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
public const string BUCKET_CONTENT_META_DATA = "content_meta_data";
private static DatabaseManager _instance;
public static DatabaseManager GetInstance()
{
NetDesktop.Activate();
NetDesktop.EnableTextLogging("logs");
return _instance ?? (_instance = new DatabaseManager());
}
public void InitializeBuckets()
{
try
{
var defaultAuthenticator = GetDefaultAuthenticator();
var dirInfo = new DirectoryInfo($"c:\\temp\\{BUCKET_CONTENT_META_DATA}");
if (!dirInfo.Parent.Exists)
{
dirInfo.Parent.Create();
}
var database = new Database(dirInfo.FullName);
// Create replicator to push and pull changes to and from the cloud
var targetEndpoint = new URLEndpoint(new Uri("ws://localhost:4985"));
var replConfig = new ReplicatorConfiguration(database, targetEndpoint)
{
Authenticator = defaultAuthenticator,
Continuous = true,
//Channels = new List<string>
//{
// "approved",
//
//}
};
var replicator = new Replicator(replConfig);
replicator.AddChangeListener((sender, args) =>
{
if (args.Status.Error != null)
{
_log.Error($"{args.Status.Error}");
}
else
{
_log.Debug(args.Status);
}
});
replicator.Start();
}
catch (Exception e)
{
_log.Error(e);
}
}
private Authenticator GetDefaultAuthenticator()
{
return new BasicAuthenticator("BigD","123456");
}
}
}
I believe you need to specify the database name in the URL for targetEndpoint.
E.g: var targetEndpoint = new URLEndpoint(new Uri("ws://localhost:4984/mydatabase"));

How to load a DLL file from a specific URL in Asp.Net Core

I would like to download a DLL file from http://localhost:8080/bin/ and instantiate classes and functions in my Asp.Net Core application.
I've made a little console application (in .NET Framwork) doing this. Here the code :
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
using (var wc = new WebClient())
{
var myDll = Assembly.Load(wc.DownloadData("http://localhost:8080/test-dll/bin/myDll.dll"));
Type t = myDll .GetType("ConsoleApplication1.Test");
// Instantiate my class
object myObject = new object();
myObject = Activator.CreateInstance(t);
}
}
}
}
Unfortunately, WebClient is not supported in .Net Core.
So, how can I load a dll file located in a specific URL and instantiate it ? (in .Net Core)
Thanks in advance for your answers !
You should be able to download file in ASP.Net core using following code.
using (HttpClient client = new HttpClient())
{
string url = "http://localhost:55272/myDll.dll";
using (var response = await client.GetAsync(url))
{
response.EnsureSuccessStatusCode();
using (var inputStream = await response.Content.ReadAsStreamAsync())
{
var mydll = AssemblyLoadContext.Default.LoadFromStream(inputStream);
}
}
}
But remember that certain file types such as .config, .dll .exe are protected in IIS and you will not be able to download such files with default settings/configuration of IIS. You need to configure that part explicitly. May be this link can be helpful on that front.
namespace ConslApp
{
class Prog
{
static void Main(string[] args)
{
using (var web = new Web())
{
var myDll = Assembly.Load(web.DownloadData("http://localhost:8080/test-dll/bin/myDll.dll"));
Type t = myDll .GetType("ConslApp.Test");
// Instantiate my class
object Obj = new object();
obj = Activator.CreateInstance(t);
}
}
}
}

What is the equivalent of HttpServiceHost in ASP.NET WebAPI?

I wanted to try out this example of a self-hosted webservice (originally written in WCF WebApi), but using the new ASP.NET WebAPI (which is the descendant of WCF WebApi).
using System;
using System.Net.Http;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using Microsoft.ApplicationServer.Http;
namespace SampleApi {
class Program {
static void Main(string[] args) {
var host = new HttpServiceHost(typeof (ApiService), "http://localhost:9000");
host.Open();
Console.WriteLine("Browse to http://localhost:9000");
Console.Read();
}
}
[ServiceContract]
public class ApiService {
[WebGet(UriTemplate = "")]
public HttpResponseMessage GetHome() {
return new HttpResponseMessage() {
Content = new StringContent("Welcome Home", Encoding.UTF8, "text/plain")
};
}
}
}
However, either I haven't NuGotten the right package, or HttpServiceHost is AWOL. (I chose the 'self hosting' variant).
What am I missing?
Please refer to this article for self-hosting:
Self-Host a Web API (C#)
The complete rewritten code for your example would be as follows:
class Program {
static void Main(string[] args) {
var config = new HttpSelfHostConfiguration("http://localhost:9000");
config.Routes.MapHttpRoute(
"API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
using (HttpSelfHostServer server = new HttpSelfHostServer(config)) {
server.OpenAsync().Wait();
Console.WriteLine("Browse to http://localhost:9000/api/service");
Console.WriteLine("Press Enter to quit.");
Console.ReadLine();
}
}
}
public class ServiceController : ApiController {
public HttpResponseMessage GetHome() {
return new HttpResponseMessage() {
Content = new StringContent("Welcome Home", Encoding.UTF8, "text/plain")
};
}
}
Hope this helps.

Categories

Resources