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

GraphQL over HTTP client integration #2538

Merged
merged 39 commits into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
44d9302
Created basic GraphQL server
jamescrosswell Jul 31, 2023
e29b658
Added Sentry
jamescrosswell Aug 1, 2023
ca8a1bb
Upgraded to latest GraphQL packages
jamescrosswell Aug 1, 2023
c6863e7
Added endpoint demonstrating use of GraphQL Client
jamescrosswell Aug 1, 2023
349f79e
Added OpenTelemetry instrumentation for GraphQL and Sentry
jamescrosswell Aug 1, 2023
cbc1aa1
Update CHANGELOG.md
jamescrosswell Aug 1, 2023
b9902b4
Merge branch 'main' into graphql
jamescrosswell Aug 1, 2023
2c610bd
Added GraphQL Client Sample
jamescrosswell Aug 2, 2023
229e6bf
Merge branch 'main' into graphql-v0.2
jamescrosswell Aug 9, 2023
da22fa8
Fixed Samples
jamescrosswell Aug 9, 2023
be5daf2
Implemented SentryGraphQlHttpMessageHandler
jamescrosswell Aug 10, 2023
31d39af
Update CHANGELOG.md
jamescrosswell Aug 10, 2023
6f6f05a
Removed DSN
jamescrosswell Aug 10, 2023
ab6984d
Merge branch 'graphql-client' of https://github.com/getsentry/sentry-…
jamescrosswell Aug 10, 2023
f7465ea
Rolled back unintentional changes to Sentry.csproj
jamescrosswell Aug 10, 2023
bd77a73
Update ApiApprovalTests.Run.Core3_1.verified.txt
jamescrosswell Aug 10, 2023
144faac
Update CHANGELOG.md
jamescrosswell Aug 10, 2023
7128c27
Merge branch 'main' into graphql-client
jamescrosswell Aug 10, 2023
f0e8e99
Fixed SentryGraphQlHttpFailedRequestHandlerTests
jamescrosswell Aug 11, 2023
be6fb2e
Added Request and Response contexts to failed requests
jamescrosswell Aug 11, 2023
b34d308
Updated verified files
jamescrosswell Aug 11, 2023
52f988c
Fixed unit tests
jamescrosswell Aug 11, 2023
740726d
Generate client errors in GraphQL Client
jamescrosswell Aug 13, 2023
c69a9cd
.
jamescrosswell Aug 13, 2023
2652a56
Fixed content not readable
jamescrosswell Aug 14, 2023
a53ebd0
Added mutation to GraphQL.Client sample
jamescrosswell Aug 14, 2023
ef28a1a
Merge branch 'main' into graphql-client
jamescrosswell Aug 14, 2023
347eef3
Renamed from Ql to QL
jamescrosswell Aug 15, 2023
4ee744a
Made GraphQLContentExtractor static
jamescrosswell Aug 15, 2023
5949aad
Merge branch 'graphql-client' of https://github.com/getsentry/sentry-…
jamescrosswell Aug 15, 2023
85eed5f
Removed redundant code
jamescrosswell Aug 15, 2023
7872c29
Integrated review feedback
jamescrosswell Aug 15, 2023
fff748f
Update GraphQLContentExtractor.cs
jamescrosswell Aug 15, 2023
7a956af
Rollback changes to breadcrumbs and defaults
jamescrosswell Aug 15, 2023
a0eeb30
Use defaults for StreamReader (except leaveopen, which must be true)
jamescrosswell Aug 15, 2023
42d1cd0
Moved GraphQL Client integration into core Sentry package
jamescrosswell Aug 16, 2023
365da70
Update ApiApprovalTests.Run.Core3_1.verified.txt
jamescrosswell Aug 17, 2023
5523f7e
Integrated final feedback
jamescrosswell Aug 17, 2023
6518ca2
Revert accidental changes to cocoa bindings
jamescrosswell Aug 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Features

- Graphql client ([#2538](https://github.com/getsentry/sentry-dotnet/pull/2538))

## 3.35.0

### Features
Expand Down
28 changes: 28 additions & 0 deletions Sentry.sln
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sentry.Samples.OpenTelemetr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Samples.OpenTelemetry.Console", "samples\Sentry.Samples.OpenTelemetry.Console\Sentry.Samples.OpenTelemetry.Console.csproj", "{D62E79F4-FC3C-4D75-ABFE-CDE76EF46DDE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Samples.GraphQL.Server", "samples\Sentry.Samples.GraphQL.Server\Sentry.Samples.GraphQL.Server.csproj", "{B3BFB7BA-1A5E-468F-8C47-F0841AA75848}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Samples.GraphQL.Client", "samples\Sentry.Samples.GraphQL.Client\Sentry.Samples.GraphQL.Client.csproj", "{B01C5D8F-62EE-4E63-AE96-745BA1D2E175}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.GraphQl", "src\Sentry.GraphQl\Sentry.GraphQl.csproj", "{A976354F-8451-4A6B-8BAC-CF94C2FCC6A7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.GraphQl.Tests", "test\Sentry.GraphQl.Tests\Sentry.GraphQl.Tests.csproj", "{1897129B-BA05-49C7-B37D-0328752C4A7C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -404,6 +412,22 @@ Global
{D62E79F4-FC3C-4D75-ABFE-CDE76EF46DDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D62E79F4-FC3C-4D75-ABFE-CDE76EF46DDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D62E79F4-FC3C-4D75-ABFE-CDE76EF46DDE}.Release|Any CPU.Build.0 = Release|Any CPU
{B3BFB7BA-1A5E-468F-8C47-F0841AA75848}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B3BFB7BA-1A5E-468F-8C47-F0841AA75848}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B3BFB7BA-1A5E-468F-8C47-F0841AA75848}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B3BFB7BA-1A5E-468F-8C47-F0841AA75848}.Release|Any CPU.Build.0 = Release|Any CPU
{B01C5D8F-62EE-4E63-AE96-745BA1D2E175}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B01C5D8F-62EE-4E63-AE96-745BA1D2E175}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B01C5D8F-62EE-4E63-AE96-745BA1D2E175}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B01C5D8F-62EE-4E63-AE96-745BA1D2E175}.Release|Any CPU.Build.0 = Release|Any CPU
{A976354F-8451-4A6B-8BAC-CF94C2FCC6A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A976354F-8451-4A6B-8BAC-CF94C2FCC6A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A976354F-8451-4A6B-8BAC-CF94C2FCC6A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A976354F-8451-4A6B-8BAC-CF94C2FCC6A7}.Release|Any CPU.Build.0 = Release|Any CPU
{1897129B-BA05-49C7-B37D-0328752C4A7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1897129B-BA05-49C7-B37D-0328752C4A7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1897129B-BA05-49C7-B37D-0328752C4A7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1897129B-BA05-49C7-B37D-0328752C4A7C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -469,6 +493,10 @@ Global
{A58DE854-6576-4E07-98BF-03B9DCCDBF9A} = {83263231-1A2A-4733-B759-EEFF14E8C5D5}
{6F791E40-49A8-4A67-81DB-6913E519310A} = {77454495-55EE-4B40-A089-71B9E8F82E89}
{D62E79F4-FC3C-4D75-ABFE-CDE76EF46DDE} = {77454495-55EE-4B40-A089-71B9E8F82E89}
{B3BFB7BA-1A5E-468F-8C47-F0841AA75848} = {77454495-55EE-4B40-A089-71B9E8F82E89}
{B01C5D8F-62EE-4E63-AE96-745BA1D2E175} = {77454495-55EE-4B40-A089-71B9E8F82E89}
{A976354F-8451-4A6B-8BAC-CF94C2FCC6A7} = {AF6AF4C7-8AA2-4D59-8064-2D79560904EB}
{1897129B-BA05-49C7-B37D-0328752C4A7C} = {83263231-1A2A-4733-B759-EEFF14E8C5D5}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0C652B1A-DF72-4EE5-A98B-194FE2C054F6}
Expand Down
67 changes: 67 additions & 0 deletions samples/Sentry.Samples.GraphQL.Client/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* This sample demonstrates using Sentry to capture traces and exceptions from a GraphQL client.
* It assumes the Sentry.Samples.GraphQL.Server is running on http://localhost:5051
* (see `/Samples/Sentry.Samples.GraphQL.Server/Properties/launchSettings.json`)
*/

using System.Text.Json;
using GraphQL;
using GraphQL.Client.Http;
using GraphQL.Client.Serializer.SystemTextJson;
using Sentry;
using Sentry.GraphQl;

SentrySdk.Init(options =>
{
// options.Dsn = "... Your DSN ...";
options.SendDefaultPii = true;
options.TracesSampleRate = 1.0;
options.EnableTracing = true;
});

var transaction = SentrySdk.StartTransaction("Program Main", "function");
SentrySdk.ConfigureScope(scope => scope.Transaction = transaction);

var graphClient = new GraphQLHttpClient(
options =>
{
options.EndPoint = new Uri("http://localhost:5051/graphql"); // Assumes Sentry.Samples.GraphQL.Server is running
options.HttpMessageHandler = new SentryGraphQlHttpMessageHandler(); // <-- Configure GraphQL use Sentry Message Handler
},
new SystemTextJsonSerializer()
);
var notesRequest = new GraphQLRequest
{
Query = @"query getAllNotes {
notes {
id,
message
}
}"
};

while(true)
{
Console.WriteLine("Press any key to continue (or `q` to quit)");
if (Console.ReadKey().KeyChar == 'q')
{
break;
}

var graphResponse = await graphClient.SendQueryAsync<NotesResult>(notesRequest);
var result = JsonSerializer.Serialize(graphResponse.Data);
Console.WriteLine(result);
}

transaction.Finish(SpanStatus.Ok);

public class Note
{
public int Id { get; set; }
public string? Message { get; set; }
}

public class NotesResult
{
public List<Note> Notes { get; set; } = new();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="GraphQL" Version="7.6.0" />
<PackageReference Include="GraphQL.Client" Version="6.0.0" />
<PackageReference Include="GraphQL.Client.Serializer.SystemTextJson" Version="6.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Sentry.GraphQl\Sentry.GraphQl.csproj" />
<ProjectReference Include="..\..\src\Sentry\Sentry.csproj" />
</ItemGroup>

</Project>
7 changes: 7 additions & 0 deletions samples/Sentry.Samples.GraphQL.Server/Notes/Note.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Sentry.Samples.GraphQL.Server.Notes;

public class Note
{
public int Id { get; set; }
public string? Message { get; set; }
}
14 changes: 14 additions & 0 deletions samples/Sentry.Samples.GraphQL.Server/Notes/NoteType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using GraphQL.Types;

namespace Sentry.Samples.GraphQL.Server.Notes;

public class NoteType : ObjectGraphType<Note>
{
public NoteType()
{
Name = "Note";
Description = "Note Type";
Field(d => d.Id, nullable: false).Description("Note Id");
Field(d => d.Message, nullable: true).Description("Note Message");
}
}
20 changes: 20 additions & 0 deletions samples/Sentry.Samples.GraphQL.Server/Notes/NotesQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using GraphQL.Types;

namespace Sentry.Samples.GraphQL.Server.Notes;

public sealed class NotesQuery : ObjectGraphType
{
private static int NextId = 0;
private readonly Lazy<List<Note>> _notes = new (
() => new List<Note>
{
new() { Id = NextId++, Message = "Hello World!" },
new() { Id = NextId++, Message = "Hello World! How are you?" }
}
);

public NotesQuery()
{
Field<ListGraphType<NoteType>>("notes").Resolve(context => _notes.Value);
}
}
11 changes: 11 additions & 0 deletions samples/Sentry.Samples.GraphQL.Server/Notes/NotesSchema.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using GraphQL.Types;

namespace Sentry.Samples.GraphQL.Server.Notes;

public class NotesSchema : Schema
{
public NotesSchema(IServiceProvider serviceProvider) : base(serviceProvider)
{
Query = serviceProvider.GetRequiredService<NotesQuery>();
}
}
117 changes: 117 additions & 0 deletions samples/Sentry.Samples.GraphQL.Server/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System.Text.Json;
using GraphQL;
using GraphQL.Client.Http;
using GraphQL.Client.Serializer.SystemTextJson;
using GraphQL.MicrosoftDI;
using GraphQL.Types;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using Sentry.OpenTelemetry;
using Sentry.Samples.GraphQL.Server.Notes;

namespace Sentry.Samples.GraphQL.Server;

public static class Program
{
public static void Main(string[] args)
{
BuildWebApplication(args).Run();
}

// public static IWebHost BuildWebHost(string[] args) =>
public static WebApplication BuildWebApplication(string[] args)
{
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenTelemetry()
.WithTracing(tracerProviderBuilder =>
tracerProviderBuilder
.AddSource(Telemetry.ActivitySource.Name)
.ConfigureResource(resource => resource.AddService(Telemetry.ServiceName))
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddSentry()
); // <-- Configure OpenTelemetry to send traces to Sentry
jamescrosswell marked this conversation as resolved.
Show resolved Hide resolved

builder.WebHost.UseSentry(o =>
{
// A DSN is required. You can set it here, or in configuration, or in an environment variable.
// o.Dsn = "...Your DSN Here...";
o.EnableTracing = true;
o.Debug = true;
o.UseOpenTelemetry(); // <-- Configure Sentry to use OpenTelemetry trace information
});

builder.Services
// add notes schema
.AddSingleton<ISchema, NotesSchema>(services =>
new NotesSchema(new SelfActivatingServiceProvider(services))
)
// register graphQL
.AddGraphQL(options => options
.AddAutoSchema<NotesSchema>()
.AddSystemTextJson()
.UseTelemetry(telemetryOptions =>
{
telemetryOptions.RecordDocument = true; // <-- Configure GraphQL to use OpenTelemetry
})
);

// Permit any Origin - not appropriate for production!!!
builder.Services.AddCors(cors => cors.AddDefaultPolicy(policy => policy.WithOrigins("*").AllowAnyHeader()));
builder.Services.AddControllers();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new()
{
Title = "Sentry.Samples.GraphQL",
Version = "v1"
});
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c =>
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Sentry.Samples.GraphQL v1"));
app.UseGraphQLAltair(); // Exposed at /ui/altair
}

app.UseAuthorization();
app.MapControllers();

app.MapGet("/", () => "Hello world!");
app.MapGet("/request", async context =>
{
var url = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.PathBase}/graphql";
var graphClient = new GraphQLHttpClient(url, new SystemTextJsonSerializer());
var notesRequest = new GraphQLRequest
{
Query = @"
{
notes {
id,
message
}
}"
};
var graphResponse = await graphClient.SendQueryAsync<NotesResult>(notesRequest);
var result = JsonSerializer.Serialize(graphResponse.Data);
await context.Response.WriteAsync(result);
});
app.MapGet("/throw", () => { throw new NotImplementedException(); });

// make sure all our schemas registered to route
app.UseGraphQL("/graphql");

return app;
}

public class NotesResult
{
public List<Note> Notes { get; set; } = new();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:19903",
"sslPort": 44302
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5051",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7146;http://localhost:5051",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="GraphQL" Version="7.6.0" />
<PackageReference Include="GraphQL.Client" Version="6.0.0" />
<PackageReference Include="GraphQL.Client.Serializer.SystemTextJson" Version="6.0.0" />
<PackageReference Include="GraphQL.MicrosoftDI" Version="7.6.0" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore" Version="7.6.0" />
<PackageReference Include="GraphQL.Server.Ui.Altair" Version="7.6.0" />
<PackageReference Include="GraphQL.SystemTextJson" Version="7.6.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.5.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.5.0-beta.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.5.0-beta.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.5" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Sentry.AspNetCore\Sentry.AspNetCore.csproj" />
<ProjectReference Include="..\..\src\Sentry.OpenTelemetry\Sentry.OpenTelemetry.csproj" />
<ProjectReference Include="..\..\src\Sentry\Sentry.csproj" />
</ItemGroup>
</Project>