Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
daniellm committed Oct 14, 2020
2 parents 06bc891 + 43780ff commit 17ba3d9
Show file tree
Hide file tree
Showing 22 changed files with 497 additions and 37 deletions.
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<Project>
<PropertyGroup>
<Company>Gigya Inc.</Company>
<Copyright2018 Gigya Inc.</Copyright>
<Copyright2020 Gigya Inc.</Copyright>
<Product>Microdot Framework</Product>
<Description>Microdot Framework</Description>
<AssemblyVersion></AssemblyVersion>
<Version>3.0.8</Version>
<Version>3.1.0</Version>
<RunSettingsFilePath>$(SolutionDir)\test.runsettings</RunSettingsFilePath>
</PropertyGroup>
</Project>
58 changes: 53 additions & 5 deletions Gigya.Microdot.Configuration/Objects/ConfigObjectCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks.Dataflow;
using Gigya.Common.Contracts.Exceptions;
using Gigya.Microdot.Interfaces;
Expand Down Expand Up @@ -210,11 +211,9 @@ public void Reload()

if (config != null && errors.Any() == false)
{
LatestNode = config;

try
{
updatedConfig = LatestNode.ToObject(ObjectType);
updatedConfig = config.ToObject(ObjectType);
}
catch (Exception ex)
{
Expand All @@ -228,22 +227,24 @@ public void Reload()

if (errors.Any() == false)
{
Latest = updatedConfig;
ValidationErrors = null;
UsageTracking.AddConfigObject(Latest, ConfigPath);
if (isCreated)
{
Log.Info(_ => _("A config object has been updated", unencryptedTags: new
{
ConfigObjectType = ObjectType.FullName,
ConfigObjectPath = ConfigPath
ConfigObjectPath = ConfigPath,
Changes = DiffJObjects(LatestNode, config, new StringBuilder(), new Stack<string>()).ToString(),
}));
}
else//It mean we are first time not need to send update messsage
{
isCreated = true;
}

LatestNode = config;
Latest = updatedConfig;
SendChangeNotification?.Invoke(Latest);
}
else
Expand All @@ -258,5 +259,52 @@ public void Reload()
}));
}
}


static StringBuilder DiffJObjects(JObject left, JObject right, StringBuilder sb, Stack<string> path)
{
var leftEnum = ((IEnumerable<KeyValuePair<string, JToken>>)left).OrderBy(_ => _.Key).GetEnumerator();
var rightEnum = ((IEnumerable<KeyValuePair<string, JToken>>)right).OrderBy(_ => _.Key).GetEnumerator();
bool moreLeft = leftEnum.MoveNext();
bool moreRight = rightEnum.MoveNext();
while (moreLeft || moreRight)
{
if (moreLeft && (!moreRight || leftEnum.Current.Key.CompareTo(rightEnum.Current.Key) < 0))
{
sb.Append(string.Join(".", path.Append(leftEnum.Current.Key))).Append(":\t").Append(JsonConvert.SerializeObject(leftEnum.Current.Value)).AppendLine("\t-->\tnull");
moreLeft = leftEnum.MoveNext();
}
else if (moreRight && (!moreLeft || leftEnum.Current.Key.CompareTo(rightEnum.Current.Key) > 0))
{
sb.Append(string.Join(".", path.Append(rightEnum.Current.Key))).Append(":\tnull\t-->\t").AppendLine(JsonConvert.SerializeObject(rightEnum.Current.Value));
moreRight = rightEnum.MoveNext();
}
else if (leftEnum.Current.Value.Type != rightEnum.Current.Value.Type)
{
sb.Append(string.Join(".", path.Append(leftEnum.Current.Key))).Append(":\t").Append(JsonConvert.SerializeObject(leftEnum.Current.Value))
.Append("\t-->\t").AppendLine(JsonConvert.SerializeObject(rightEnum.Current.Value));
moreLeft = leftEnum.MoveNext();
moreRight = rightEnum.MoveNext();
}
else if (leftEnum.Current.Value.Type != JTokenType.Object)
{
if (!JToken.DeepEquals(leftEnum.Current.Value, rightEnum.Current.Value))
sb.Append(string.Join(".", path.Append(leftEnum.Current.Key))).Append(":\t").Append(JsonConvert.SerializeObject(leftEnum.Current.Value))
.Append("\t-->\t").AppendLine(JsonConvert.SerializeObject(rightEnum.Current.Value));
moreLeft = leftEnum.MoveNext();
moreRight = rightEnum.MoveNext();
}
else
{
path.Push(leftEnum.Current.Key);
DiffJObjects((JObject)leftEnum.Current.Value, (JObject)rightEnum.Current.Value, sb, path);
path.Pop();
moreLeft = leftEnum.MoveNext();
moreRight = rightEnum.MoveNext();
}
}

return sb;
}
}
}
21 changes: 13 additions & 8 deletions Gigya.Microdot.Hosting/HttpService/HttpServiceListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
using Gigya.Microdot.SharedLogic.HttpService;
using Gigya.Microdot.SharedLogic.Measurement;
using Gigya.Microdot.SharedLogic.Security;
using Gigya.Microdot.SharedLogic.Utils;
using Gigya.ServiceContract.Exceptions;
using Metrics;
using Newtonsoft.Json;
Expand Down Expand Up @@ -276,13 +277,14 @@ private async Task HandleRequest(HttpListenerContext context)
TracingContext.SpanStartTime = requestData.TracingData.SpanStartTime;
TracingContext.AbandonRequestBy = requestData.TracingData.AbandonRequestBy;
TracingContext.SetParentSpan(requestData.TracingData.SpanID?? Guid.NewGuid().ToString("N"));
TracingContext.SetOverrides(requestData.Overrides);
if (requestData.TracingData.Tags != null)
TracingContext.Tags = new ContextTags(requestData.TracingData.Tags);
TracingContext.AdditionalProperties = requestData.TracingData.AdditionalProperties;

callEvent.ServiceMethodSchema = context.Request.IsSecureConnection ? "HTTPS" : "HTTP";

SetCallEventRequestData(callEvent, requestData);

TracingContext.SetOverrides(requestData.Overrides);

serviceMethod = ServiceEndPointDefinition.Resolve(requestData.Target);
callEvent.CalledServiceName = serviceMethod.GrainInterfaceType.Name;
methodName = serviceMethod.ServiceInterfaceMethod.Name;
Expand Down Expand Up @@ -370,11 +372,14 @@ private static object[] GetConvertedAndDefaultArguments(MethodInfo method, objec

private void SetCallEventRequestData(ServiceCallEvent callEvent, HttpServiceRequest requestData)
{
callEvent.ClientMetadata = requestData.TracingData;
callEvent.ServiceMethod = requestData.Target?.MethodName;
callEvent.RequestId = requestData.TracingData?.RequestID;
callEvent.SpanId = requestData.TracingData?.SpanID;
callEvent.ParentSpanId = requestData.TracingData?.ParentSpanID;
callEvent.ClientMetadata = requestData.TracingData;
callEvent.ServiceMethod = requestData.Target?.MethodName;
callEvent.RequestId = requestData.TracingData?.RequestID;
callEvent.SpanId = requestData.TracingData?.SpanID;
callEvent.ParentSpanId = requestData.TracingData?.ParentSpanID;
callEvent.ContextUnencryptedTags = requestData.TracingData?.Tags?.GetUnencryptedTags();
callEvent.ContextTagsEncrypted = requestData.TracingData?.Tags?.GetEncryptedTags();
callEvent.UnknownTracingData = requestData.TracingData?.AdditionalProperties;
}

private async Task<bool> TryHandleSpecialEndpoints(HttpListenerContext context)
Expand Down
5 changes: 5 additions & 0 deletions Gigya.Microdot.ServiceDiscovery/Config/DiscoveryConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ public class DiscoveryConfig : IConfigObject
/// </summary>
public bool TryHttps { get; set; }

/// <summary>
/// The frequency in which the service proxy will try to send an HTTPS request in minutes
/// </summary>
public int TryHttpsIntervalInMinutes { get; set; } = 1;

/// <summary>
/// Controls the client verification logic for the server certificate.
/// Default behavior is to validate that the server domain matches the certificate domain.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ public class ServiceDiscoveryConfig
/// </summary>
public bool? TryHttps { get; set; }

/// <summary>
/// The frequency in which the service proxy will try to send an HTTPS request in minutes
/// </summary>
public int? TryHttpsIntervalInMinutes { get; set; }

/// <summary>
/// Controls the client verification logic for the server certificate.
/// Defaults to null, will override the global settings for this service if set to anything but null.
Expand Down
10 changes: 8 additions & 2 deletions Gigya.Microdot.ServiceProxy/ServiceProxyProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public class ServiceProxyProvider : IDisposable, IServiceProxyProvider


private DateTime _lastHttpsTestTime = DateTime.MinValue;
private readonly TimeSpan _httpsTestInterval = TimeSpan.FromMinutes(1);
private readonly TimeSpan _httpsTestInterval;

private readonly Func<HttpClientConfiguration, HttpMessageHandler> _httpMessageHandlerFactory;

Expand Down Expand Up @@ -159,6 +159,10 @@ public ServiceProxyProvider(string serviceName, IEventPublisher<ClientCallEvent>
_httpMessageHandlerFactory = messageHandlerFactory;

ServiceDiscovery = serviceDiscoveryFactory(serviceName, ValidateReachability);

var globalConfig = GetDiscoveryConfig();
var serviceConfig = GetConfig();
_httpsTestInterval = TimeSpan.FromMinutes(serviceConfig.TryHttpsIntervalInMinutes?? globalConfig.TryHttpsIntervalInMinutes);
}

/// <summary>
Expand Down Expand Up @@ -353,7 +357,9 @@ private async Task<object> InvokeCore(HttpServiceRequest request, Type resultRet
SpanID = Guid.NewGuid().ToString("N"), //Each call is new span
ParentSpanID = TracingContext.TryGetParentSpanID(),
SpanStartTime = DateTimeOffset.UtcNow,
AbandonRequestBy = TracingContext.AbandonRequestBy
AbandonRequestBy = TracingContext.AbandonRequestBy,
AdditionalProperties = TracingContext.AdditionalProperties,
Tags = TracingContext.TagsOrNull?.Tags,
};
PrepareRequest?.Invoke(request);

Expand Down
103 changes: 103 additions & 0 deletions Gigya.Microdot.SharedLogic/Events/ContextTags.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using Gigya.Common.Contracts.Exceptions;
using Gigya.Microdot.SharedLogic.Utils;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Gigya.Microdot.SharedLogic.Events
{
public struct ContextTag
{
public object Value;
public bool IsEncrypted;
}

public class ContextTags
{
internal Dictionary<string, ContextTag> Tags;
public ContextTags() { Tags = new Dictionary<string, ContextTag>(); }
public ContextTags(Dictionary<string, ContextTag> tags) { Tags = tags; }

public IEnumerable<KeyValuePair<string, object>> GetUnencryptedTags() => Tags.GetUnencryptedTags();

public IEnumerable<KeyValuePair<string, object>> GetEncryptedTags() => Tags.GetEncryptedTags();

public bool TryGet(string key, out object value)
{
if (Tags.TryGetValue(key, out var item))
{
value = item.Value;
return true;
}
else
{
value = null;
return false;
}
}

public bool TryGet<T>(string key, out T value)
{
if (Tags.TryGetValue(key, out var item))
{
try
{
value = (T)Convert.ChangeType(item.Value, typeof(T));
return true;
}
catch (Exception ex)
{
throw new ProgrammaticException("Cannot obtain tag with desired type", unencrypted: new Tags() {
["error"] = ex.Message,
["actualType"] = item.Value?.GetType().ToString(),
["desiredType"] = typeof(T).Name,
["tagName"] = key,
},
encrypted: new Tags() { ["tagValue"] = item.Value?.ToString() });
}
}
else
{
value = default(T);
return false;
}
}

public IDisposable SetEncryptedTag<T>(string key, T value)
{
return Tag(key, value, IsEncrypted: true);
}

public IDisposable SetUnencryptedTag<T>(string key, T value)
{
return Tag(key, value, IsEncrypted: false);
}

IDisposable Tag<T>(string key, T value, bool IsEncrypted)
{
if (!typeof(T).IsValueType && !(value is string))
throw new ProgrammaticException("Tags can only be pritmive values or strings");

if (Tags.TryGetValue(key, out var currentTag))
{
Tags[key] = new ContextTag { Value = value, IsEncrypted = IsEncrypted };

// On dispose, we restore the tag to its previous value
return new DisposableAction<bool>(
state: true,
dispose: s => Tags[key] = new ContextTag { Value = currentTag.Value, IsEncrypted = currentTag.IsEncrypted });
}
else
{
Tags[key] = new ContextTag { Value = value, IsEncrypted = IsEncrypted };

// On dispose, we remove the value
return new DisposableAction<bool>(
state: true,
dispose: s => Tags.Remove(key));
}

}

}
}
52 changes: 52 additions & 0 deletions Gigya.Microdot.SharedLogic/Events/DisposableAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;

namespace Gigya.Microdot.SharedLogic.Events
{
/// <summary>
/// A disposable action allows the developer to use it as part of a using statement to call a function on creation and another on disposal.
/// </summary>
class DisposableAction<T> : IDisposable
{
private readonly T _state;
private Action<T> _dispose;

/// <summary>
/// Initializes a new instance of the <see cref="DisposableAction"/> class.
/// </summary>
/// <param name="dispose">
/// The dispose.
/// </param>
public DisposableAction(T state, Action<T> dispose)
{
if (dispose == null) throw new ArgumentNullException("dispose");
_state = state;
_dispose = dispose;
}


/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

/// <summary>
/// The dispose.
/// </summary>
/// <param name="disposing">
/// The disposing.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_dispose?.Invoke(_state);
_dispose = null;
}
}
}
}
10 changes: 10 additions & 0 deletions Gigya.Microdot.SharedLogic/Events/Event.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ public class Event : IEvent
[EventField(EventConsts.parentSpanID)]
public string ParentSpanId { get; set; } = TracingContext.TryGetParentSpanID();

[EventField(EventConsts.unknownTracingData, Encrypt = true)]
public Dictionary<string, object> UnknownTracingData { get; set; } = TracingContext.AdditionalProperties;


//============ PUBLISHER INFO ===============

/// <summary>The name of the reporting system (comments/socialize/hades/mongo etc)</summary>
Expand Down Expand Up @@ -233,5 +237,11 @@ public string ExceptionStackTrace

/// <summary>Whether exception stack traces should be excluded. Note: can be overridden by derived classes.</summary>
public virtual bool ShouldExcludeStackTrace => Configuration.ExcludeStackTraceRule?.IsMatch(ErrCode_.ToString()) == true;

[EventField(EventConsts.context, AppendTypeSuffix = true)]
public IEnumerable<KeyValuePair<string, object>> ContextUnencryptedTags { get; set; } = TracingContext.TagsOrNull?.GetUnencryptedTags();

[EventField(EventConsts.context, Encrypt = true)]
public IEnumerable<KeyValuePair<string, object>> ContextTagsEncrypted { get; set; } = TracingContext.TagsOrNull?.GetEncryptedTags();
}
}
Loading

0 comments on commit 17ba3d9

Please sign in to comment.