Unverified Commit 1fb4378d authored by Lemon's avatar Lemon Committed by GitHub

Refactor SkyWalking.Diagnostics (#35)

* Downgrade dependencies

* Refactor SkyWalking.Diagnostics

* Add ParameterBinder

* Fix null parameter

* Add unit tests for SkyWalking.Diagnostics

* Fix property binding
parent 426f0103
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
......
......@@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using SkyWalking.AspNetCore;
using SkyWalking.Diagnostics.CAP;
namespace SkyWalking.Sample.Backend
{
......@@ -21,17 +20,11 @@ namespace SkyWalking.Sample.Backend
{
services.AddMvc();
//services.AddCap(x =>
//{
// x.UseKafka("192.168.10.110:9092");
// x.UseMySql("Server=192.168.10.110;Database=testcap;UserId=root;Password=123123;");
//});
services.AddSkyWalking(option =>
{
option.DirectServers = "localhost:11800";
option.ApplicationCode = "asp-net-core-backend";
});//.AddCap();
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
......@@ -43,8 +36,6 @@ namespace SkyWalking.Sample.Backend
}
app.UseMvc();
// app.UseCap();
}
}
}
\ No newline at end of file
......@@ -14,5 +14,5 @@
<ItemGroup>
<ProjectReference Include="..\SkyWalking.NetworkProtocol.Trace\SkyWalking.NetworkProtocol.Trace.csproj" />
<ProjectReference Include="..\SkyWalking.NetworkProtocol\SkyWalking.NetworkProtocol.csproj" />
</ItemGroup>
</ItemGroup>
</Project>
\ No newline at end of file
......@@ -18,7 +18,6 @@
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DiagnosticAdapter;
using SkyWalking.Context;
using SkyWalking.Context.Tag;
using SkyWalking.Context.Trace;
......
......@@ -39,7 +39,7 @@ namespace SkyWalking.AspNetCore
public static SkyWalkingBuilder AddDiagnostics(this SkyWalkingBuilder builder)
{
builder.Services.AddSingleton<TracingDiagnosticObserver, AdatpeTracingDiagnosticObserver>();
builder.Services.AddSingleton<TracingDiagnosticProcessorObserver>();
return builder;
}
......
......@@ -15,7 +15,6 @@
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="2.1.0-preview2-final" />
<PackageReference Include="Microsoft.Extensions.Http" Version="2.1.0-preview2-final" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.1.0-preview2-final" />
<PackageReference Include="Microsoft.Extensions.Options" Version="2.1.0-preview2-final" />
......
......@@ -33,11 +33,11 @@ namespace SkyWalking.AspNetCore
{
public class SkyWalkingHostedService : IHostedService
{
private readonly TracingDiagnosticObserver _diagnosticObserver;
private readonly TracingDiagnosticProcessorObserver _diagnosticObserver;
private readonly ILogger _logger;
public SkyWalkingHostedService(IOptions<SkyWalkingOptions> options, IHostingEnvironment hostingEnvironment,
TracingDiagnosticObserver diagnosticObserver, ILoggerFactory loggerFactory)
TracingDiagnosticProcessorObserver diagnosticObserver, ILoggerFactory loggerFactory)
{
if (string.IsNullOrEmpty(options.Value.DirectServers))
......
/*
* Licensed to the OpenSkywalking under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
namespace SkyWalking.Diagnostics
{
public class AnonymousObject : ParameterBinder
{
public override object Resolve(object value)
{
return value;
}
}
}
\ No newline at end of file
......@@ -16,22 +16,17 @@
*
*/
using System.Collections.Generic;
using System.Diagnostics;
using SkyWalking.Diagnostics;
using System;
namespace SkyWalking.AspNetCore.Diagnostics
namespace SkyWalking.Diagnostics
{
public class AdatpeTracingDiagnosticObserver : TracingDiagnosticObserver
public class DiagnosticName :Attribute
{
public AdatpeTracingDiagnosticObserver(IEnumerable<ITracingDiagnosticProcessor> tracingDiagnosticProcessors)
: base(tracingDiagnosticProcessors)
{
}
public string Name { get; }
protected override void OnNext(DiagnosticListener listener, ITracingDiagnosticProcessor diagnosticProcessor)
public DiagnosticName(string name)
{
listener.SubscribeWithAdapter(diagnosticProcessor);
Name = name;
}
}
}
\ No newline at end of file
/*
* Licensed to the OpenSkywalking under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
namespace SkyWalking.Diagnostics
{
public interface IParameterResolver
{
object Resolve(object value);
}
}
\ No newline at end of file
/*
* Licensed to the OpenSkywalking under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
namespace SkyWalking.Diagnostics
{
public class NullParameterResolver : IParameterResolver
{
public object Resolve(object value)
{
return null;
}
}
}
\ No newline at end of file
/*
* Licensed to the OpenSkywalking under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
namespace SkyWalking.Diagnostics
{
public class ObjectAttribute : ParameterBinder
{
public Type TargetType { get; set; }
public override object Resolve(object value)
{
if (TargetType == null || value == null)
{
return value;
}
if (TargetType == value.GetType())
{
return value;
}
if (TargetType.IsInstanceOfType(value))
{
return value;
}
return null;
}
}
}
\ No newline at end of file
/*
* Licensed to the OpenSkywalking under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
namespace SkyWalking.Diagnostics
{
public abstract class ParameterBinder : Attribute, IParameterResolver
{
public abstract object Resolve(object value);
}
}
\ No newline at end of file
/*
* Licensed to the OpenSkywalking under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
namespace SkyWalking.Diagnostics
{
public class PropertyAttribute : ParameterBinder
{
public string Name { get; set; }
public override object Resolve(object value)
{
if (value == null || Name == null)
{
return null;
}
var property = value.GetType().GetProperty(Name);
return property?.GetValue(value);
}
}
}
\ No newline at end of file
/*
* Licensed to the OpenSkywalking under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace SkyWalking.Diagnostics
{
internal class TracingDiagnosticMethod
{
private readonly MethodInfo _method;
private readonly ITracingDiagnosticProcessor _diagnosticProcessor;
private readonly string _diagnosticName;
private readonly IParameterResolver[] _parameterResolvers;
public TracingDiagnosticMethod(ITracingDiagnosticProcessor diagnosticProcessor, MethodInfo method,
string diagnosticName)
{
_diagnosticProcessor = diagnosticProcessor;
_method = method;
_diagnosticName = diagnosticName;
_parameterResolvers = GetParameterResolvers(method).ToArray();
}
public void Invoke(string diagnosticName, object value)
{
if (_diagnosticName != diagnosticName)
{
return;
}
var args = new object[_parameterResolvers.Length];
for (var i = 0; i < _parameterResolvers.Length; i++)
{
args[i] = _parameterResolvers[i].Resolve(value);
}
_method.Invoke(_diagnosticProcessor, args);
}
private static IEnumerable<IParameterResolver> GetParameterResolvers(MethodInfo methodInfo)
{
foreach (var parameter in methodInfo.GetParameters())
{
var binder = parameter.GetCustomAttribute<ParameterBinder>();
if (binder != null)
{
if(binder is ObjectAttribute objectBinder)
{
if (objectBinder.TargetType == null)
{
objectBinder.TargetType = parameter.ParameterType;
}
}
if(binder is PropertyAttribute propertyBinder)
{
if (propertyBinder.Name == null)
{
propertyBinder.Name = parameter.Name;
}
}
yield return binder;
}
else
{
yield return new NullParameterResolver();
}
}
}
}
}
\ No newline at end of file
/*
* Licensed to the OpenSkywalking under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
namespace SkyWalking.Diagnostics
{
internal class TracingDiagnosticMethodCollection : IEnumerable<TracingDiagnosticMethod>
{
private readonly List<TracingDiagnosticMethod> _methods;
public TracingDiagnosticMethodCollection(ITracingDiagnosticProcessor diagnosticProcessor)
{
_methods = new List<TracingDiagnosticMethod>();
foreach (var method in diagnosticProcessor.GetType().GetMethods())
{
var diagnosticName = method.GetCustomAttribute<DiagnosticName>();
if(diagnosticName==null)
continue;
_methods.Add(new TracingDiagnosticMethod(diagnosticProcessor, method, diagnosticName.Name));
}
}
public IEnumerator<TracingDiagnosticMethod> GetEnumerator()
{
return _methods.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _methods.GetEnumerator();
}
}
}
\ No newline at end of file
......@@ -18,22 +18,16 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using SkyWalking.Logging;
using SkyWalking.Utils;
namespace SkyWalking.Diagnostics
{
public abstract class TracingDiagnosticObserver : IObserver<DiagnosticListener>
internal class TracingDiagnosticObserver : IObserver<KeyValuePair<string, object>>
{
private static readonly ILogger _logger = LogManager.GetLogger<TracingDiagnosticObserver>();
private readonly TracingDiagnosticMethodCollection _methodCollection;
private readonly IEnumerable<ITracingDiagnosticProcessor> _tracingDiagnosticProcessors;
public TracingDiagnosticObserver(IEnumerable<ITracingDiagnosticProcessor> tracingDiagnosticProcessors)
public TracingDiagnosticObserver(ITracingDiagnosticProcessor tracingDiagnosticProcessor)
{
_tracingDiagnosticProcessors = tracingDiagnosticProcessors ??
throw new ArgumentNullException(nameof(tracingDiagnosticProcessors));
_methodCollection = new TracingDiagnosticMethodCollection(tracingDiagnosticProcessor);
}
public void OnCompleted()
......@@ -44,19 +38,12 @@ namespace SkyWalking.Diagnostics
{
}
public void OnNext(DiagnosticListener listener)
public void OnNext(KeyValuePair<string, object> value)
{
foreach (var diagnosticProcessor in _tracingDiagnosticProcessors.Distinct(x => x.ListenerName))
foreach (var method in _methodCollection)
{
if (listener.Name == diagnosticProcessor.ListenerName)
{
OnNext(listener, diagnosticProcessor);
_logger.Debug($"TracingDiagnosticObserver subscribe diagnosticListener named [{diagnosticProcessor.ListenerName}].");
}
method.Invoke(value.Key, value.Value);
}
}
protected abstract void OnNext(DiagnosticListener listener,
ITracingDiagnosticProcessor diagnosticProcessor);
}
}
\ No newline at end of file
/*
* Licensed to the OpenSkywalking under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using SkyWalking.Logging;
using SkyWalking.Utils;
namespace SkyWalking.Diagnostics
{
public class TracingDiagnosticProcessorObserver : IObserver<DiagnosticListener>
{
private static readonly ILogger _logger = LogManager.GetLogger<TracingDiagnosticProcessorObserver>();
private readonly IEnumerable<ITracingDiagnosticProcessor> _tracingDiagnosticProcessors;
public TracingDiagnosticProcessorObserver(IEnumerable<ITracingDiagnosticProcessor> tracingDiagnosticProcessors)
{
_tracingDiagnosticProcessors = tracingDiagnosticProcessors ??
throw new ArgumentNullException(nameof(tracingDiagnosticProcessors));
}
public void OnCompleted()
{
}
public void OnError(Exception error)
{
}
public void OnNext(DiagnosticListener listener)
{
foreach (var diagnosticProcessor in _tracingDiagnosticProcessors.Distinct(x => x.ListenerName))
{
if (listener.Name == diagnosticProcessor.ListenerName)
{
Subscribe(listener, diagnosticProcessor);
_logger.Debug(
$"TracingDiagnosticObserver subscribe diagnosticListener named [{diagnosticProcessor.ListenerName}].");
}
}
}
protected virtual void Subscribe(DiagnosticListener listener,
ITracingDiagnosticProcessor diagnosticProcessor)
{
listener.Subscribe(new TracingDiagnosticObserver(diagnosticProcessor));
}
}
}
\ No newline at end of file
......@@ -24,7 +24,7 @@ namespace SkyWalking.Logging
{
public ILogger CreateLogger(Type type)
{
return null;
return new NullLogger();
}
}
}
\ No newline at end of file
......@@ -13,6 +13,8 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\SkyWalking.Abstractions\SkyWalking.Abstractions.csproj" />
<ProjectReference Include="..\SkyWalking.NetworkProtocol.Trace\SkyWalking.NetworkProtocol.Trace.csproj" />
<ProjectReference Include="..\SkyWalking.NetworkProtocol\SkyWalking.NetworkProtocol.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Nito.AsyncEx.Coordination" Version="5.0.0-pre-05" />
......
......@@ -19,7 +19,6 @@
using System;
using DotNetCore.CAP.Diagnostics;
using DotNetCore.CAP.Infrastructure;
using Microsoft.Extensions.DiagnosticAdapter;
using SkyWalking.Context;
using SkyWalking.Context.Tag;
using SkyWalking.Context.Trace;
......
......@@ -17,7 +17,6 @@
<ItemGroup>
<PackageReference Include="DotNetCore.CAP" Version="2.2.2" />
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="2.1.0-preview2-final" />
</ItemGroup>
<ItemGroup>
......
......@@ -16,9 +16,7 @@
*
*/
using System.Diagnostics;
using System.Net.Http;
using Microsoft.Extensions.DiagnosticAdapter;
using SkyWalking.Context;
using SkyWalking.Context.Tag;
using SkyWalking.Context.Trace;
......
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\common.props" />
<PropertyGroup>
......@@ -13,10 +14,6 @@
<RootNamespace>SkyWalking.Diagnostics.HttpClient</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="2.1.0-preview2-final" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SkyWalking.Abstractions\SkyWalking.Abstractions.csproj" />
<ProjectReference Include="..\SkyWalking.Core\SkyWalking.Core.csproj" />
......
using System.Diagnostics;
namespace SkyWalking.Core.Tests.Diagnostics
{
public class FakeDiagnosticListener : DiagnosticListener
{
public const string ListenerName = "SkyWalking.Core.Tests.Diagnostics";
public const string Executing = "Executing";
public const string Executed = "Executed";
public FakeDiagnosticListener() : base(ListenerName)
{
}
}
}
\ No newline at end of file
using System;
namespace SkyWalking.Core.Tests.Diagnostics
{
public class FakeDiagnosticListenerData
{
public string Name { get; set; }
public DateTime Timestamp { get; set; }
}
}
\ No newline at end of file
using System;
using SkyWalking.Diagnostics;
using Xunit;
namespace SkyWalking.Core.Tests.Diagnostics
{
public class FakeTracingDiagnosticProcessor : ITracingDiagnosticProcessor
{
public string ListenerName { get; } = FakeDiagnosticListener.ListenerName;
public DateTime Timestamp { get; set; }
[DiagnosticName(FakeDiagnosticListener.Executing)]
public void Executing(
[PropertyAttribute(Name = "Name")] string eventName,
[Property] DateTime Timestamp)
{
Assert.Equal("Executing", eventName);
this.Timestamp = Timestamp;
}
[DiagnosticName(FakeDiagnosticListener.Executed)]
public void Executed([Object] FakeDiagnosticListenerData data)
{
Assert.Equal("Executed", data.Name);
Timestamp = data.Timestamp;
}
}
}
\ No newline at end of file
using System;
using System.Diagnostics;
using SkyWalking.Diagnostics;
using Xunit;
namespace SkyWalking.Core.Tests.Diagnostics
{
public class TracingDiagnosticProcessorObserverTests
{
[Fact]
public void Property_Binder_Invoke_Test()
{
var listener = new FakeDiagnosticListener();
var fakeProcessor = new FakeTracingDiagnosticProcessor();
var observer = new TracingDiagnosticProcessorObserver(new ITracingDiagnosticProcessor[] {fakeProcessor});
DiagnosticListener.AllListeners.Subscribe(observer);
var timeStamp = DateTime.Now;
listener.Write(FakeDiagnosticListener.Executing,
new
{
Name = FakeDiagnosticListener.Executing,
Timestamp = timeStamp
});
Assert.Equal(timeStamp, fakeProcessor.Timestamp);
}
[Fact]
public void Object_Binder_Invoke_Test()
{
var listener = new FakeDiagnosticListener();
var fakeProcessor = new FakeTracingDiagnosticProcessor();
var observer = new TracingDiagnosticProcessorObserver(new ITracingDiagnosticProcessor[] {fakeProcessor});
DiagnosticListener.AllListeners.Subscribe(observer);
var timeStamp = DateTime.Now;
listener.Write(FakeDiagnosticListener.Executed,
new FakeDiagnosticListenerData
{
Name = FakeDiagnosticListener.Executed,
Timestamp = timeStamp
});
Assert.Equal(timeStamp, fakeProcessor.Timestamp);
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment