Skip to content

Commit 448ade6

Browse files
committed
Adding metrics logging
1 parent 0cfc3f7 commit 448ade6

13 files changed

+175
-1
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using Microsoft.Azure.WebJobs.Script.Diagnostics;
6+
7+
namespace WebJobs.Script.WebHost.Diagnostics
8+
{
9+
public class WebHostMetricsLogger : IMetricsLogger
10+
{
11+
public void BeginEvent(MetricEvent metricEvent)
12+
{
13+
// TODO
14+
FunctionStartedEvent startedEvent = metricEvent as FunctionStartedEvent;
15+
if (startedEvent != null)
16+
{
17+
startedEvent.StartTime = DateTime.Now;
18+
}
19+
}
20+
21+
public void EndEvent(MetricEvent metricEvent)
22+
{
23+
// TODO
24+
FunctionStartedEvent startedEvent = metricEvent as FunctionStartedEvent;
25+
if (startedEvent != null)
26+
{
27+
startedEvent.EndTime = DateTime.Now;
28+
}
29+
}
30+
}
31+
}

src/WebJobs.Script.WebHost/WebJobs.Script.WebHost.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@
237237
<Compile Include="Controllers\AdminController.cs" />
238238
<Compile Include="Controllers\FunctionsController.cs" />
239239
<Compile Include="Controllers\HomeController.cs" />
240+
<Compile Include="Diagnostics\WebHostMetricsLogger.cs" />
240241
<Compile Include="Filters\AuthorizationLevelAttribute.cs" />
241242
<Compile Include="FunctionSecrets.cs" />
242243
<Compile Include="Global.asax.cs">

src/WebJobs.Script.WebHost/WebScriptHostManager.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
using System.Net.Http;
99
using System.Threading;
1010
using System.Threading.Tasks;
11+
using Microsoft.Azure.WebJobs;
1112
using Microsoft.Azure.WebJobs.Script;
1213
using Microsoft.Azure.WebJobs.Script.Description;
14+
using Microsoft.Azure.WebJobs.Script.Diagnostics;
15+
using WebJobs.Script.WebHost.Diagnostics;
1316

1417
namespace WebJobs.Script.WebHost
1518
{
@@ -74,6 +77,14 @@ public FunctionDescriptor GetHttpFunctionOrNull(Uri uri)
7477
return function;
7578
}
7679

80+
protected override void OnInitializeConfig(JobHostConfiguration config)
81+
{
82+
base.OnInitializeConfig(config);
83+
84+
// Add our WebHost specific services
85+
config.AddService<IMetricsLogger>(new WebHostMetricsLogger());
86+
}
87+
7788
protected override void OnHostStarted()
7889
{
7990
base.OnHostStarted();

src/WebJobs.Script/Description/CSharp/CSharpFunctionInvoker.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using System.Threading.Tasks;
1414
using Microsoft.Azure.WebJobs.Host;
1515
using Microsoft.Azure.WebJobs.Script.Binding;
16+
using Microsoft.Azure.WebJobs.Script.Diagnostics;
1617
using Microsoft.CodeAnalysis;
1718
using Microsoft.CodeAnalysis.CSharp;
1819
using Microsoft.CodeAnalysis.CSharp.Scripting;
@@ -31,6 +32,7 @@ public class CSharpFunctionInvoker : ScriptFunctionInvokerBase
3132
private readonly Collection<FunctionBinding> _inputBindings;
3233
private readonly Collection<FunctionBinding> _outputBindings;
3334
private readonly IFunctionEntryPointResolver _functionEntryPointResolver;
35+
private readonly IMetricsLogger _metrics;
3436

3537
private MethodInfo _function;
3638
private CSharpFunctionSignature _functionSignature;
@@ -53,6 +55,7 @@ internal CSharpFunctionInvoker(ScriptHost host, FunctionMetadata functionMetadat
5355
_inputBindings = inputBindings;
5456
_outputBindings = outputBindings;
5557
_triggerInputName = GetTriggerInputName(functionMetadata);
58+
_metrics = host.ScriptConfig.HostConfig.GetService<IMetricsLogger>();
5659

5760
InitializeFileWatcherIfEnabled();
5861
_resultProcessor = CreateResultProcessor();
@@ -150,6 +153,9 @@ private void RestorePackages()
150153

151154
public override async Task Invoke(object[] parameters)
152155
{
156+
FunctionStartedEvent startedEvent = new FunctionStartedEvent(Metadata);
157+
_metrics.BeginEvent(startedEvent);
158+
153159
try
154160
{
155161
TraceWriter.Verbose("Function started");
@@ -175,9 +181,17 @@ public override async Task Invoke(object[] parameters)
175181
catch (Exception ex)
176182
{
177183
TraceWriter.Error(ex.Message, ex is CompilationErrorException ? null : ex);
184+
185+
startedEvent.Success = false;
186+
TraceWriter.Error(ex.Message, ex);
187+
178188
TraceWriter.Verbose("Function completed (Failure)");
179189
throw;
180190
}
191+
finally
192+
{
193+
_metrics.EndEvent(startedEvent);
194+
}
181195
}
182196

183197
private object[] ProcessInputParameters(object[] parameters)

src/WebJobs.Script/Description/NodeFunctionInvoker.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using EdgeJs;
1717
using Microsoft.Azure.WebJobs.Host;
1818
using Microsoft.Azure.WebJobs.Script.Binding;
19+
using Microsoft.Azure.WebJobs.Script.Diagnostics;
1920
using Newtonsoft.Json;
2021

2122
namespace Microsoft.Azure.WebJobs.Script.Description
@@ -28,6 +29,7 @@ public class NodeFunctionInvoker : ScriptFunctionInvokerBase
2829
private readonly string _script;
2930
private readonly DictionaryJsonConverter _dictionaryJsonConverter = new DictionaryJsonConverter();
3031
private readonly BindingMetadata _trigger;
32+
private readonly IMetricsLogger _metrics;
3133

3234
private Func<object, Task<object>> _scriptFunc;
3335
private Func<object, Task<object>> _clearRequireCache;
@@ -55,6 +57,7 @@ internal NodeFunctionInvoker(ScriptHost host, BindingMetadata trigger, FunctionM
5557
_script = string.Format(CultureInfo.InvariantCulture, _functionTemplate, scriptFilePath);
5658
_inputBindings = inputBindings;
5759
_outputBindings = outputBindings;
60+
_metrics = host.ScriptConfig.HostConfig.GetService<IMetricsLogger>();
5861

5962
InitializeFileWatcherIfEnabled();
6063
}
@@ -93,6 +96,9 @@ public override async Task Invoke(object[] parameters)
9396
IBinder binder = (IBinder)parameters[2];
9497
ExecutionContext functionExecutionContext = (ExecutionContext)parameters[3];
9598

99+
FunctionStartedEvent startedEvent = new FunctionStartedEvent(Metadata);
100+
_metrics.BeginEvent(startedEvent);
101+
96102
try
97103
{
98104
TraceWriter.Verbose(string.Format("Function started"));
@@ -113,10 +119,15 @@ public override async Task Invoke(object[] parameters)
113119
}
114120
catch (Exception ex)
115121
{
122+
startedEvent.Success = false;
116123
TraceWriter.Error(ex.Message, ex);
117124
TraceWriter.Verbose(string.Format("Function completed (Failure)"));
118125
throw;
119126
}
127+
finally
128+
{
129+
_metrics.EndEvent(startedEvent);
130+
}
120131
}
121132

122133
private async Task ProcessInputBindingsAsync(IBinder binder, Dictionary<string, object> executionContext, Dictionary<string, string> bindingData)

src/WebJobs.Script/Description/ScriptFunctionInvoker.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using System.Threading.Tasks;
1313
using Microsoft.Azure.WebJobs.Host;
1414
using Microsoft.Azure.WebJobs.Script.Binding;
15+
using Microsoft.Azure.WebJobs.Script.Diagnostics;
1516

1617
namespace Microsoft.Azure.WebJobs.Script.Description
1718
{
@@ -23,6 +24,8 @@ public class ScriptFunctionInvoker : ScriptFunctionInvokerBase
2324
private static string[] _supportedScriptTypes = new string[] { "ps1", "cmd", "bat", "py", "php", "sh", "fsx" };
2425
private readonly string _scriptFilePath;
2526
private readonly string _scriptType;
27+
private readonly IMetricsLogger _metrics;
28+
2629
private readonly Collection<FunctionBinding> _inputBindings;
2730
private readonly Collection<FunctionBinding> _outputBindings;
2831

@@ -33,6 +36,7 @@ internal ScriptFunctionInvoker(string scriptFilePath, ScriptHost host, FunctionM
3336
_scriptType = Path.GetExtension(_scriptFilePath).ToLower(CultureInfo.InvariantCulture).TrimStart('.');
3437
_inputBindings = inputBindings;
3538
_outputBindings = outputBindings;
39+
_metrics = host.ScriptConfig.HostConfig.GetService<IMetricsLogger>();
3640
}
3741

3842
public static bool IsSupportedScriptType(string extension)
@@ -87,6 +91,9 @@ internal async Task ExecuteScriptAsync(string path, string arguments, object[] i
8791
IBinder binder = (IBinder)invocationParameters[2];
8892
ExecutionContext functionExecutionContext = (ExecutionContext)invocationParameters[3];
8993

94+
FunctionStartedEvent startedEvent = new FunctionStartedEvent(Metadata);
95+
_metrics.BeginEvent(startedEvent);
96+
9097
// perform any required input conversions
9198
string stdin = null;
9299
if (input != null)
@@ -131,8 +138,14 @@ internal async Task ExecuteScriptAsync(string path, string arguments, object[] i
131138
}
132139
process.WaitForExit();
133140

134-
if (process.ExitCode != 0)
141+
bool failed = process.ExitCode != 0;
142+
startedEvent.Success = !failed;
143+
_metrics.EndEvent(startedEvent);
144+
145+
if (failed)
135146
{
147+
startedEvent.Success = false;
148+
136149
string error = process.StandardError.ReadToEnd();
137150
TraceWriter.Error(error);
138151
TraceWriter.Verbose(string.Format("Function completed (Failure)"));
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using Microsoft.Azure.WebJobs.Script.Description;
5+
6+
namespace Microsoft.Azure.WebJobs.Script.Diagnostics
7+
{
8+
public class FunctionStartedEvent : MetricEvent
9+
{
10+
public FunctionStartedEvent(FunctionMetadata functionMetadata)
11+
{
12+
FunctionMetadata = functionMetadata;
13+
Success = true;
14+
}
15+
16+
public FunctionMetadata FunctionMetadata { get; private set; }
17+
18+
public bool Success { get; set; }
19+
}
20+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.Azure.WebJobs.Script.Diagnostics
5+
{
6+
/// <summary>
7+
/// Defines an interface for emitting metric events from the
8+
/// script runtime for later aggregation and reporting.
9+
/// </summary>
10+
public interface IMetricsLogger
11+
{
12+
/// <summary>
13+
/// Begins an event.
14+
/// </summary>
15+
/// <param name="metricEvent">The event.</param>
16+
void BeginEvent(MetricEvent metricEvent);
17+
18+
/// <summary>
19+
/// Completes a previously started event.
20+
/// </summary>
21+
/// <param name="metricEvent">A previously started event.</param>
22+
void EndEvent(MetricEvent metricEvent);
23+
}
24+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
6+
namespace Microsoft.Azure.WebJobs.Script.Diagnostics
7+
{
8+
public abstract class MetricEvent
9+
{
10+
public DateTime StartTime { get; set; }
11+
12+
public DateTime EndTime { get; set; }
13+
}
14+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.Azure.WebJobs.Script.Diagnostics
5+
{
6+
/// <summary>
7+
/// Default implementation of <see cref="IMetricsLogger"/> that doesn't do any logging.
8+
/// </summary>
9+
public class MetricsLogger : IMetricsLogger
10+
{
11+
public void BeginEvent(MetricEvent metricEvent)
12+
{
13+
}
14+
15+
public void EndEvent(MetricEvent metricEvent)
16+
{
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)