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

Version 12.0.0 preparation #360

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,45 @@ namespace commercetools.Api.IntegrationTests;

public class LoggingTest
{
[Fact]
public async void DefaultLogger()
{
var configuration = new ConfigurationBuilder().
AddJsonFile("appsettings.test.Development.json", true).
AddEnvironmentVariables().
AddUserSecrets<ServiceProviderFixture>().
AddEnvironmentVariables("CTP_").
Build();
var clientConfiguration = configuration.GetSection("Client").Get<ClientConfiguration>();
var loggerClientConf = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>()
{
{ "LoggerClient:ClientId", clientConfiguration.ClientId},
{ "LoggerClient:ClientSecret", clientConfiguration.ClientSecret},
{ "LoggerClient:ProjectKey", clientConfiguration.ProjectKey},
})
.Build();
var logger = new TestLogger();
var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddFilter("System.Net.Http.HttpClient", LogLevel.None) // disable HTTP client default logging
.AddProvider(new TestLoggerProvider(logger));
});
var s = new ServiceCollection();
s.AddSingleton(loggerFactory);
s.UseCommercetoolsApi(loggerClientConf, "LoggerClient");
var p = s.BuildServiceProvider();

var apiRoot = p.GetService<ProjectApiRoot>();

await apiRoot.Get().ExecuteAsync();

var messages = logger.GetLogMessages();
Assert.StartsWith("GET https://api.europe-west1.gcp.commercetools.com/" + clientConfiguration.ProjectKey, messages.TrimEnd());
}


[Fact]
public async void CustomLogger()
{
Expand Down Expand Up @@ -55,7 +94,7 @@ public async void CustomLogger()
var messages = logger.GetLogMessages();
Assert.Equal("GET https://api.europe-west1.gcp.commercetools.com/" + clientConfiguration.ProjectKey, messages.TrimEnd());
}

public class CustomLoggerHandler : DelegatingHandler
{
private readonly ILogger logger;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using commercetools.Sdk.Api.Models.Errors;
using commercetools.Base.Client;
using commercetools.Base.Client.Error;
using commercetools.Sdk.Api;
using commercetools.Sdk.Api.Serialization;
using Microsoft.Extensions.Configuration;
Expand All @@ -9,7 +11,7 @@

namespace commercetools.Api.IntegrationTests
{
public class ServiceProviderFixture
public sealed class ServiceProviderFixture
{
private readonly ServiceProvider serviceProvider;
private readonly IConfiguration configuration;
Expand All @@ -20,20 +22,44 @@ public ServiceProviderFixture()

//services.AddLogging(configure => configure.AddConsole());
this.configuration = new ConfigurationBuilder().
AddInMemoryCollection(
new Dictionary<string, string>()
{
{ "Logging:LogLevel:commercetoolsLoggerHandler", "Warning"},
{ "Logging:LogLevel:System.Net.Http.HttpClient", "Warning"},
}).
AddJsonFile("appsettings.test.Development.json", true).
AddEnvironmentVariables().
AddUserSecrets<ServiceProviderFixture>().
AddEnvironmentVariables("CTP_").
Build();

var useStreamClient = Enum.Parse<ClientType>(configuration.GetValue("ClientType", "String")) == ClientType.Stream;
var useStreamClient = Enum.Parse<ClientType>(configuration.GetValue("ClientType", "String")) != ClientType.String;
services.UseCommercetoolsApi(configuration, "Client", options: new ClientOptions { ReadResponseAsStream = useStreamClient });
services.AddLogging(c => c.AddConfiguration(configuration.GetSection("Logging")));
services.AddLogging(c => c.AddProvider(new InMemoryLoggerProvider()));
services.AddLogging(c => c.AddSimpleConsole(o =>
{
o.UseUtcTimestamp = true;
o.IncludeScopes = true;
o.TimestampFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFK ";
o.SingleLine = true;
}));
services.SetupClient(
"MeClient",
errorTypeMapper => typeof(ErrorResponse),
s => s.GetService<IApiSerializerService>()
);
services.AddSingleton<ILoggerHandlerOptions>(new LoggerHandlerOptions()
{
ResponseLogEvent = LogLevel.Information,
DefaultExceptionLogEvent = LogLevel.Warning,
ExceptionLogEvents = new Dictionary<System.Type, LogLevel>()
{
{ typeof(NotFoundException), LogLevel.Information },
{ typeof(ConcurrentModificationException), LogLevel.Information}
}
});
this.serviceProvider = services.BuildServiceProvider();

//set default ProjectKey
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace commercetools.GraphQL.Api.IntegrationTests
{
public class ServiceProviderFixture
public sealed class ServiceProviderFixture
{
private readonly ServiceProvider serviceProvider;
private readonly IConfiguration configuration;
Expand All @@ -24,7 +24,7 @@ public ServiceProviderFixture()
AddUserSecrets<ServiceProviderFixture>().
AddEnvironmentVariables("CTP_").
Build();
var useStreamClient = Enum.Parse<ClientType>(configuration.GetValue("ClientType", "String")) == ClientType.Stream;
var useStreamClient = Enum.Parse<ClientType>(configuration.GetValue("ClientType", "String")) != ClientType.String;

services.UseCommercetoolsApi(configuration, "Client", options: new ClientOptions { ReadResponseAsStream = useStreamClient });
services.AddLogging(c => c.AddProvider(new InMemoryLoggerProvider()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace commercetools.ImportApi.IntegrationTests
{
public class ServiceProviderFixture
public sealed class ServiceProviderFixture
{
private readonly ServiceProvider serviceProvider;
private readonly IConfiguration configuration;
Expand All @@ -22,7 +22,7 @@ public ServiceProviderFixture()
AddEnvironmentVariables("CTP_").
Build();

var useStreamClient = Enum.Parse<ClientType>(configuration.GetValue("ClientType", "String")) == ClientType.Stream;
var useStreamClient = Enum.Parse<ClientType>(configuration.GetValue("ClientType", "String")) != ClientType.String;
services.UseCommercetoolsImportApi(configuration, "ImportClient", options: new ClientOptions { ReadResponseAsStream = useStreamClient });
this.serviceProvider = services.BuildServiceProvider();

Expand Down
1 change: 0 additions & 1 deletion commercetools.Sdk/commercetools.Base.Client/ApiMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ public virtual HttpRequestMessage Build()
{
var requestPath = new Uri(RequestUrl + ToQueryString(QueryParams), UriKind.Relative);
var request = new HttpRequestMessage();
request.Version = HttpVersion.Version20;
request.Method = this.Method;
request.RequestUri = requestPath;
request.AddHeaders(Headers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public class ClientOptions
public DecompressionMethods DecompressionMethods { get; set; } =
DecompressionMethods.Deflate | DecompressionMethods.GZip;

public bool ReadResponseAsStream { get; set; } = false;
public bool ReadResponseAsStream { get; set; } = true;

public Version UseHttpVersion { get; set; } = null;
public Version UseHttpVersion { get; set; } = HttpVersion.Version20;
}
}
111 changes: 111 additions & 0 deletions commercetools.Sdk/commercetools.Base.Client/DefaultHttpLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace commercetools.Base.Client
{
public class DefaultHttpLogger : IHttpLogger
{
public async Task LogRequestBody(ILogger logger, LogLevel logLevel, HttpRequestMessage request)
{
if (logger.IsEnabled(logLevel))
{
var body = await (request.Content?.ReadAsStringAsync() ?? Task.FromResult(""));
logger.Log(logLevel, "{HttpMethod} {Uri} {Headers} {Body}", request.Method.Method,
request.RequestUri.AbsoluteUri, RedactAuthorizationHeader(request.Headers), SecuredBody(body));
}
}

public async Task LogResponseBody(ILogger logger, LogLevel logLevel, HttpRequestMessage request, HttpResponseMessage response, long elapsed)
{
if (logger.IsEnabled(logLevel))
{
var body = await (response.Content?.ReadAsStringAsync() ?? Task.FromResult(""));
logger.Log(logLevel, "{HttpMethod} {Uri} {StatusCode} {Timing} {Headers} {Body}", request.Method.Method,
request.RequestUri.AbsoluteUri, (int)response.StatusCode, elapsed, RedactAuthorizationHeader(request.Headers), SecuredBody(body));
}
}

public void Log(ILogger logger, LogLevel logLevel, HttpRequestMessage request)
{
if (logger.IsEnabled(logLevel))
{
logger.Log(logLevel, "{HttpMethod} {Uri} {Headers}", request.Method.Method,
request.RequestUri.AbsoluteUri, RedactAuthorizationHeader(request.Headers));
}
}

public void Log(ILogger logger, LogLevel level, HttpRequestMessage request, HttpResponseMessage response, long elapsed)
{
if (logger.IsEnabled(level))
{
logger.Log(level, "{HttpMethod} {Uri} {StatusCode} {Timing} {CorrelationId} {ServerTiming}", request.Method.Method,
request.RequestUri.AbsoluteUri, (int)response.StatusCode, elapsed, GetCorrelationId(response.Headers), GetServerTiming(response.Headers));
}
}

public void Log(ILogger logger, LogLevel logLevel, HttpRequestMessage request, ApiHttpException exception, long elapsed)
{
if (logger.IsEnabled(logLevel))
{
logger.Log(logLevel, "{HttpMethod} {Uri} {StatusCode} {Timing} {CorrelationId} {ServerTiming}", request.Method.Method,
request.RequestUri.AbsoluteUri, exception.StatusCode, elapsed, GetCorrelationId(exception.Headers), GetServerTiming(exception.Headers));
}
}


private static string RedactAuthorizationHeader(HttpRequestHeaders headers)
{
var headString = from header in headers
where header.Key.ToLower() != "authorization"
select header.Key + ": " + string.Join(", ", header.Value);

return "[" + string.Join(", ", headString) + "]";
}

private static string SecuredBody(string body)
{
if (body != null)
return Regex.Replace(body, "(\"\\w*([Pp]ass|access_token|refresh_token)\\w*\"):\\W*\"[^\"]*\"",
"$1:\"**removed from output**\"");
return null;
}

private static string GetCorrelationId(ApiHttpHeaders headers)
{
return headers.GetFirst("X-Correlation-Id") ?? "-";
}

private static string GetCorrelationId(HttpResponseHeaders headers)
{
return GetHeader(headers, "X-Correlation-ID");
}

private static string GetHeader(HttpResponseHeaders headers, string headerName)
{
var headerValue = "-";

if (headers.TryGetValues(headerName, out var values))
{
headerValue = values.First();
}

return headerValue;
}

private static string GetServerTiming(HttpResponseHeaders headers)
{
return GetHeader(headers, "Server-Timing");
}

private static string GetServerTiming(ApiHttpHeaders headers)
{
return headers.GetFirst("Server-Timing") ?? "-";
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,29 +105,36 @@ public static IHttpClientBuilder SetupClient(this IServiceCollection services, s
options ??= new ClientOptions();
services.AddSingleton<IUserAgentProvider, UserAgentProvider>();
services.AddSingleton<ILoggerHandlerFactory, LoggerHandlerFactory>();
services.AddSingleton<IHttpLogger, DefaultHttpLogger>();
services.AddSingleton<ILoggerHandlerOptions, LoggerHandlerOptions>();
var httpClientBuilder = services.AddHttpClient(clientName)
.ConfigureHttpClient((provider, client) =>
{
if (options.DecompressionMethods.HasFlag(DecompressionMethods.GZip))
{
client.DefaultRequestHeaders.AcceptEncoding.ParseAdd("gzip");
}

if (options.DecompressionMethods.HasFlag(DecompressionMethods.Deflate))
{
client.DefaultRequestHeaders.AcceptEncoding.ParseAdd("deflate");
}

client.DefaultRequestVersion = options.UseHttpVersion;

var userAgentProvider = provider.GetService<IUserAgentProvider>() ?? new UserAgentProvider();
client.DefaultRequestHeaders.UserAgent.ParseAdd(userAgentProvider.UserAgent);
})
.ConfigureHttpMessageHandlerBuilder(builder =>
{
builder.PrimaryHandler = new HttpClientHandler
builder.PrimaryHandler = new SocketsHttpHandler()
{
AutomaticDecompression = options.DecompressionMethods
};
})
.AddHttpMessageHandler(c => new ErrorHandler(message => serializerFactory(c).Deserialize(errorResponseTypeMapper(message), message.ExtractResponseBody())))
.AddHttpMessageHandler(c => c.GetService<ILoggerHandlerFactory>().Create());
.AddHttpMessageHandler(c => c.GetService<ILoggerHandlerFactory>().Create())
.AddHttpMessageHandler(c => new ErrorHandler(message =>
serializerFactory(c).Deserialize(errorResponseTypeMapper(message), message.ExtractResponseBody())));

return httpClientBuilder;
}
Expand Down
18 changes: 18 additions & 0 deletions commercetools.Sdk/commercetools.Base.Client/IHttpLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace commercetools.Base.Client
{
public interface IHttpLogger
{
void Log(ILogger logger, LogLevel level, HttpRequestMessage request);
void Log(ILogger logger, LogLevel level, HttpRequestMessage request, HttpResponseMessage response, long elapsed);
void Log(ILogger logger, LogLevel logLevel, HttpRequestMessage request, ApiHttpException exception, long elapsed);

Task LogRequestBody(ILogger logger, LogLevel logLevel, HttpRequestMessage request);

Task LogResponseBody(ILogger logger, LogLevel logLevel, HttpRequestMessage request,
HttpResponseMessage response, long elapsed);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;

namespace commercetools.Base.Client
{
public interface ILoggerHandlerOptions
{
LogLevel ResponseLogEvent { get; }
LogLevel DefaultExceptionLogEvent { get; }
Dictionary<Type, LogLevel> ExceptionLogEvents { get; }
}
}
Loading
Loading