Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Jaeger exporter implementation #132

Merged

Conversation

EGHornbostel
Copy link
Contributor

#77

This PR creates a Jaeger exporter which adds support for CNCF Jaeger.

@EGHornbostel
Copy link
Contributor Author

Not sure what's going on. I can't seem to get this build to work on windows... fails for me even on the master branch.

@EGHornbostel
Copy link
Contributor Author

EGHornbostel commented Jul 3, 2019

OK... figured out why I couldn't compile under windows. Seems like SourceLink isn't happy on my windows machine.

Anyway, after removing that reference so I could compile, I found out why the dotNet (windows) build is failing. Despite what they advertise, the Thrift library I'm referencing doesn't really work with dotNet Framework 4.6... so I need to figure out a workaround.

@EGHornbostel
Copy link
Contributor Author

EGHornbostel commented Jul 3, 2019

I've mentioned this a little in the Gitter chat, but in order to make the Jaeger Exporter work with both .net Framework 4.6 and dotnet standard 2, I had to pull in the Thrift source and include it in a /lib folder so that I could conditionally add System.Net.Http when compiling under Windows. see: https://github.com/open-telemetry/opentelemetry-dotnet/blob/0d872b48ce599eab896a2ea01c912a6097cf8520/lib/Thrift/Thrift.csproj

Does anyone have any thoughts on possible alternative ways to make this work?


<PropertyGroup>
<TargetFrameworks>net46;netstandard2.0</TargetFrameworks>
<TargetFrameworks Condition="$(OS) != 'Windows_NT'">netstandard2.0</TargetFrameworks>
Copy link

Choose a reason for hiding this comment

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

Suggested change
<TargetFrameworks Condition="$(OS) != 'Windows_NT'">netstandard2.0</TargetFrameworks>

Copy link
Member

Choose a reason for hiding this comment

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

Nitpicking here but I believe keeping the current value of TargetFrameworks and appending if condition is true makes a bit more sense:

  <PropertyGroup>
    <TargetFrameworks>netstandard2.0</TargetFrameworks>
  </PropertyGroup>
  <PropertyGroup Condition="'$(OS)' == 'Windows_NT'">
    <TargetFrameworks>net46;$(TargetFrameworks)</TargetFrameworks>
</PropertyGroup>

The reason being, when we add netstandard2.1, you just need to add to the top TargetFrameworks/add only once.

Although I'm not sure what's the reason to not compile for net46 on non Windows. ReferenceAssemblies can be used for that. Tests can run on Mono.

Copy link
Contributor Author

@EGHornbostel EGHornbostel Jul 8, 2019

Choose a reason for hiding this comment

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

OK... figured out why I couldn't compile under windows. Seems like SourceLink isn't happy on my windows machine.

could you please share what is the problem? I don't have issues on my windows machine and I wonder if some prerequsites are missing from our contributor's guide.

I was getting this error:

The "Microsoft.Build.Tasks.Git.LocateRepository" task failed unexpectedly.

I can't give you specifics right now, since I just realized that I left my external drive that contains my windows image at home. I'll update this note with a more detailed error when I get home.

Copy link

Choose a reason for hiding this comment

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

here dotnet/sourcelink#107 they tell "SourceLink requires .NET Core 2.1.300."

Do you have it installed on your machine? this version or later? Can you please check?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

here dotnet/sourcelink#107 they tell "SourceLink requires .NET Core 2.1.300."

Do you have it installed on your machine? this version or later? Can you please check?

Hi, yeah, I actually checked that the first thing when I switched over to Windows.

I just finally figured it out. I didn't have Git installed on my Windows VM because I've been managing source control through my MacOS host. I didn't even catch this when tried to clone the repo, since I cloned it using Visual Studio 2019's "Clone or check out code" feature, and Visual Studio 2019 is able to clone without Git installed.

So, it may seem like a silly thing to add to the CONTRIBUTING.md, but we might want to add a line item to install the Git command line tools. Especially since Visual Studio 2019 can now interact with Git without the tools installed.

<TargetFrameworks Condition="$(OS) != 'Windows_NT'">netstandard2.0</TargetFrameworks>
</PropertyGroup>

<ItemGroup Condition="$(OS) == 'Windows_NT'">
Copy link

Choose a reason for hiding this comment

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

change it to

  <ItemGroup Condition="'$(TargetFramework)' == 'net46'">
    <Reference Include="System.Net.Http" />
  </ItemGroup>

otherwise it bring .NET Core nuget package, while what we need is the lib that is part of installed .NET on 4.6

this.isInitialized = false;
}

// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
Copy link

Choose a reason for hiding this comment

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

is it still WIP or TODOs can be cleaned up? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can clean them up. I was thinking to leave it as WIP, but it's unnecessary. It's the standard dispose pattern that anyone should know what to do with.

@lmolkova
Copy link

lmolkova commented Jul 4, 2019

've mentioned this a little in the Gitter chat, but in order to make the Jaeger Exporter work with both .net Framework 4.6 and dotnet standard 2, I had to pull in the Thrift source and include it in a /lib folder so that I could conditionally add System.Net.Http when compiling under Windows. see: https://github.com/open-telemetry/opentelemetry-dotnet/blob/0d872b48ce599eab896a2ea01c912a6097cf8520/lib/Thrift/Thrift.csproj

Does anyone have any thoughts on possible alternative ways to make this work?

I'm surprised that Thrift is not available on nuget packages. Is it correct that there is no 'official' source for this packages? Also, do I understand correctly that thrift doesn't change much? I.e. existing implementation won't require changes, correct?

I think in this case including source code and compiling it the only reasonable option.
Can you leave some comments saving where you took this code from? Commit id?
So if it breaks, at least we'll know where to check for possible fixes.

Also, there are not many tests written for exporters and it is going to hunt us down eventually. Could you please write some unit tests and maybe some integration test, so when we change things (in API e.g. ) we know we didn't break the exported.

@lmolkova
Copy link

lmolkova commented Jul 4, 2019

OK... figured out why I couldn't compile under windows. Seems like SourceLink isn't happy on my windows machine.

could you please share what is the problem? I don't have issues on my windows machine and I wonder if some prerequsites are missing from our contributor's guide.

Copy link

@lmolkova lmolkova left a comment

Choose a reason for hiding this comment

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

Thanks a lot for the contribution! I've left some comments - let's discuss.

Copy link
Member

@bruno-garcia bruno-garcia left a comment

Choose a reason for hiding this comment

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

Left a couple notes. I hope you find them helpful.


<PropertyGroup>
<TargetFrameworks>net46;netstandard2.0</TargetFrameworks>
<TargetFrameworks Condition="$(OS) != 'Windows_NT'">netstandard2.0</TargetFrameworks>
Copy link
Member

Choose a reason for hiding this comment

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

Nitpicking here but I believe keeping the current value of TargetFrameworks and appending if condition is true makes a bit more sense:

  <PropertyGroup>
    <TargetFrameworks>netstandard2.0</TargetFrameworks>
  </PropertyGroup>
  <PropertyGroup Condition="'$(OS)' == 'Windows_NT'">
    <TargetFrameworks>net46;$(TargetFrameworks)</TargetFrameworks>
</PropertyGroup>

The reason being, when we add netstandard2.1, you just need to add to the top TargetFrameworks/add only once.

Although I'm not sure what's the reason to not compile for net46 on non Windows. ReferenceAssemblies can be used for that. Tests can run on Mono.

lib/Thrift/Transports/Client/TStreamClientTransport.cs Outdated Show resolved Hide resolved
lib/Thrift/Transports/Client/TStreamClientTransport.cs Outdated Show resolved Hide resolved
return await InputStream.ReadAsync(buffer, offset, length, cancellationToken);
}

public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
public override Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)

"Cannot read from null inputstream");
}

await OutputStream.WriteAsync(buffer, offset, length, cancellationToken);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
await OutputStream.WriteAsync(buffer, offset, length, cancellationToken);
return OutputStream.WriteAsync(buffer, offset, length, cancellationToken);

}
}

public override void Close()
Copy link
Member

Choose a reason for hiding this comment

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

nit: Could be single liner with expression bodied member:

Suggested change
public override void Close()
public override void Close() => _stream?.Dispose();

}
catch (SocketException sx)
{
throw new TTransportException("Could not accept on listening socket: " + sx.Message);
Copy link
Member

Choose a reason for hiding this comment

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

Does TTransportException take the inner exception as a second argument?

try
{
TFramedClientTransport tSocketTransport = null;
var tcpClient = await _server.AcceptTcpClientAsync();
Copy link
Member

Choose a reason for hiding this comment

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

I believe in libraries we should still be using ConfigureAwait(false) to save someone calling .Result and deadlocking.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@bruno-garcia done... did a massive regex search and replace to fix the missing ConfigureAwait(false) all over the Thrift code.

// ReSharper disable once InconsistentNaming
public class TTransportFactory
{
public virtual TClientTransport GetTransport(TClientTransport trans)
Copy link
Member

Choose a reason for hiding this comment

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

All these methods with a single return or single assignment could be expression bodied member:

Suggested change
public virtual TClientTransport GetTransport(TClientTransport trans)
public virtual TClientTransport GetTransport(TClientTransport trans) => trans;

<ItemGroup Condition="$(OS) == 'Windows_NT'">
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<ItemGroup Condition="'$(TargetFramework)' == 'net46'">
<Reference Include="System.Net.Http" Version="4.3.4" />
Copy link

Choose a reason for hiding this comment

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

please remove version, it is not needed

<Reference Include="System.Net.Http" />

@@ -5,8 +5,8 @@
<TargetFrameworks Condition="$(OS) != 'Windows_NT'">netstandard2.0</TargetFrameworks>
Copy link

Choose a reason for hiding this comment

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

<TargetFrameworks Condition="$(OS) != 'Windows_NT'">netstandard2.0</TargetFrameworks>

is not needed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, after removing this and compiling, the code fails in .net standard 2.0. I double checked and this is the same pattern we're using in all the other projects in the solution. Should we be doing something else?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Correction: it doesn't fail in .net standard 2.0, it fails on any non-windows machine that cannot host .net Framework 4.5. The build command sees all the target frameworks and attempts to build them all. Since Framework 4.5 is not available, the framework 4.5 part of the build fails.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sample output:

/usr/local/share/dotnet/sdk/2.2.300/Microsoft.Common.CurrentVersion.targets(1175,5): error MSB3644: The reference assemblies for framework ".NETFramework,Version=v4.6" were not found. To resolve this, install the SDK or Targeting Pack for this framework version or retarget your application to a version of the framework for which you have the SDK or Targeting Pack installed. Note that assemblies will be resolved from the Global Assembly Cache (GAC) and will be used in place of reference assemblies. Therefore your assembly may not be correctly targeted for the framework you intend. [/Users/eg.hornbostel/dev/opentelemetry-dotnet/lib/Thrift/Thrift.csproj]
    14 Warning(s)
    1 Error(s)

Choose a reason for hiding this comment

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

ok, i see, so you are building on Mac i guess and this protects your build. Sorry for misleading advice, please put it back.

@EGHornbostel
Copy link
Contributor Author

EGHornbostel commented Jul 8, 2019

I'm surprised that Thrift is not available on nuget packages. Is it correct that there is no 'official' source for this packages? Also, do I understand correctly that thrift doesn't change much? I.e. existing implementation won't require changes, correct?

Thrift is available as a NuGet package, but it doesn't appear to work correctly in Framework 4.6

I actually created this fork from another fork in Uber's own source code for Jaeger's client.

And you are correct. As far as I could tell, Thrift hasn't changed much in the last few years.

I think in this case including source code and compiling it the only reasonable option.
Can you leave some comments saving where you took this code from? Commit id?
So if it breaks, at least we'll know where to check for possible fixes.

I took the code from Jaeger's source:

https://github.com/jaegertracing/jaeger-client-csharp

commit ID

0794ea71cb6e58f7bf0f0ef2c0c8ceceb1d8b6d9

Path to their Thrift fork is
src/Thrift

Also, there are not many tests written for exporters and it is going to hunt us down eventually. Could you please write some unit tests and maybe some integration test, so when we change things (in API e.g. ) we know we didn't break the exported.

Agreed. I'll start working on unit tests.

Do we have any examples of good integration tests in this solution that I can use as a guide?

@EGHornbostel
Copy link
Contributor Author

EGHornbostel commented Jul 8, 2019

@lmolkova I've switched the project from using the NuGet version of System.Net.Http over to the direct Framework reference. However, I'm now getting a new build issue on windows.

It appears that Thrift needs access to HttpClientHandler.ClientCertificates This doesn't exist in .net Framework 4.6, but only in Framework 4.7 and above (see https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler.clientcertificates?view=netframework-4.8). The nuget package seems to be the only thing that works without code changes.

If we would like to consider a code change, it would require vastly rewriting this Thrift class to remove the dependency with HttpClientHandler and rewrite it to use HttpWebRequest instead.

Thoughts?

@EGHornbostel
Copy link
Contributor Author

@lmolkova I found some bare-bones integration tests with the UDP transport in the Jaeger client. I ported it over. I also created my own test for whether or not the Thrift payload is encoded consistently given the same exact data. Is this enough?

@EGHornbostel
Copy link
Contributor Author

@bruno-garcia I've made changes based on your input. Thanks very much for your help. You've been most helpful to a guy who's been away from the C# game for 5 years.

// limitations under the License.
// </copyright>

namespace OpenTelemetry.Exporter.Jaeger.Implimentation
Copy link

Choose a reason for hiding this comment

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

Namespace Typo: Implimentation -> Implementation

@austinlparker
Copy link
Member

This looks OK overall, could you fix the merge conflict on the sln? I'll hold off on more merges to keep things stable.

@EGHornbostel
Copy link
Contributor Author

This looks OK overall, could you fix the merge conflict on the sln? I'll hold off on more merges to keep things stable.

.sln merge conflicts are the best.

@austinlparker
Copy link
Member

@lmolkova wanted to make sure you were cool with merging this since you requested changes

@austinlparker austinlparker merged commit 8e1d8fa into open-telemetry:master Jul 24, 2019
@EGHornbostel EGHornbostel deleted the jaeger-exporter branch July 24, 2019 20:31
Yun-Ting pushed a commit to Yun-Ting/opentelemetry-dotnet that referenced this pull request Oct 13, 2022
…ting to a client or duplex streaming service fails (open-telemetry#132)

Any exceptions during a write to a clientstreaming or duplexstreaming RPC are not tracked. They are bubbling up to the caller and we are losing the opportunity to record the correct status code and properly stop the activity. Before this change, the newly added tests would fail with a status code of (1) cancelled which was getting set during Dispose instead of proactively at the time of the failure.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants