private void EndFunction(FunctionInstanceLogEntry item)
        {
            item.Properties.TryGetValue(Key, out (FunctionStartedEvent, object)invocationTuple);

            bool success      = item.ErrorDetails == null;
            var  startedEvent = invocationTuple.Item1;

            startedEvent.Success = success;

            var    function     = startedEvent.FunctionMetadata;
            string eventName    = success ? MetricEventNames.FunctionInvokeSucceeded : MetricEventNames.FunctionInvokeFailed;
            string functionName = function != null ? function.Name : string.Empty;
            string data         = string.Format(Microsoft.Azure.WebJobs.Script.Properties.Resources.FunctionInvocationMetricsData, startedEvent.FunctionMetadata.Language, functionName, success, Stopwatch.IsHighResolution);

            _metrics.LogEvent(eventName, startedEvent.FunctionName, data);

            startedEvent.Data = data;
            _metrics.EndEvent(startedEvent);

            var invokeLatencyEvent = invocationTuple.Item2;

            if (invokeLatencyEvent is MetricEvent metricEvent)
            {
                metricEvent.Data = data;
            }

            _metrics.EndEvent(invokeLatencyEvent);
        }
Exemple #2
0
        // Called on success and failure
        public void End(bool success)
        {
            startedEvent.Success = success;
            string  eventName = success ? MetricEventNames.FunctionInvokeSucceeded : MetricEventNames.FunctionInvokeFailed;
            dynamic data      = new JObject();

            data.Language     = startedEvent.FunctionMetadata.Language;
            data.FunctionName = _metadata != null ? _metadata.Name : string.Empty;
            data.Success      = success;
            string jsonData = data.ToString();

            startedEvent.Data = jsonData;
            _metrics.LogEvent(eventName, startedEvent.FunctionName, jsonData);

            _metrics.EndEvent(startedEvent);

            if (invokeLatencyEvent != null)
            {
                MetricEvent metricEvent = invokeLatencyEvent as MetricEvent;
                if (metricEvent != null)
                {
                    metricEvent.Data = jsonData;
                }
                _metrics.EndEvent(invokeLatencyEvent);
            }
        }
Exemple #3
0
        // Called on success and failure
        public void End(bool success)
        {
            _startedEvent.Success = success;
            string eventName = success ? MetricEventNames.FunctionInvokeSucceeded : MetricEventNames.FunctionInvokeFailed;

            var data = new JObject
            {
                ["Language"]     = _startedEvent.FunctionMetadata.Language,
                ["FunctionName"] = _metadata != null ? _metadata.Name : string.Empty,
                ["Success"]      = success,
                ["IsStopwatchHighResolution"] = Stopwatch.IsHighResolution
            };

            string jsonData = data.ToString();

            _startedEvent.Data = jsonData;
            _metrics.LogEvent(eventName, _startedEvent.FunctionName, jsonData);

            _metrics.EndEvent(_startedEvent);

            if (_invokeLatencyEvent is MetricEvent metricEvent)
            {
                metricEvent.Data = jsonData;
            }

            _metrics.EndEvent(_invokeLatencyEvent);
        }
Exemple #4
0
        // Called on success and failure
        public void End(bool success)
        {
            startedEvent.Success = success;
            _metrics.EndEvent(startedEvent);

            if (invokeLatencyEvent != null)
            {
                _metrics.EndEvent(invokeLatencyEvent);
            }
        }
        public void Decorator_EndEventWithMetricEvent_Called()
        {
            Guid                 invocationId = Guid.NewGuid();
            FunctionMetadata     meta         = new FunctionMetadata();
            FunctionStartedEvent evt          = new FunctionStartedEvent(invocationId, meta);

            _metricsLogger.Setup(a => a.EndEvent(evt));
            _metricsLoggerDecorator.EndEvent(evt);
            _metricsLogger.Verify(a => a.EndEvent(evt), Times.Once());
            _metricsLogger.Reset();
        }
        // Called on success and failure
        public void End(bool success)
        {
            _logInfo.LogFunctionResult(success, _invocationId.ToString(), _invocationStopWatch.ElapsedMilliseconds);

            startedEvent.Success = success;
            _metrics.EndEvent(startedEvent);

            if (invokeLatencyEvent != null)
            {
                _metrics.EndEvent(invokeLatencyEvent);
            }
        }
        // Called on success and failure
        public void End(bool success)
        {
            startedEvent.Success = success;
            string eventName = success ? MetricEventNames.FunctionInvokeSucceeded : MetricEventNames.FunctionInvokeFailed;

            _metrics.LogEvent(eventName, startedEvent.FunctionName);

            _metrics.EndEvent(startedEvent);

            if (invokeLatencyEvent != null)
            {
                _metrics.EndEvent(invokeLatencyEvent);
            }
        }
Exemple #8
0
 public void Dispose()
 {
     if (_metricsLogger != null && _metricEvent != null)
     {
         _metricsLogger.EndEvent(_metricEvent);
     }
 }
Exemple #9
0
        public override async Task Invoke(object[] parameters)
        {
            // TODO: Refactor common code for providers.
            object           input       = parameters[0];
            TraceWriter      traceWriter = (TraceWriter)parameters[1];
            Binder           binder      = (Binder)parameters[2];
            ExecutionContext functionExecutionContext = (ExecutionContext)parameters[3];
            string           invocationId             = functionExecutionContext.InvocationId.ToString();

            FunctionStartedEvent startedEvent = new FunctionStartedEvent(functionExecutionContext.InvocationId, Metadata);

            _metrics.BeginEvent(startedEvent);

            try
            {
                TraceWriter.Info(string.Format("Function started (Id={0})", invocationId));

                object convertedInput = ConvertInput(input);
                ApplyBindingData(convertedInput, binder);
                Dictionary <string, object> bindingData = binder.BindingData;
                bindingData["InvocationId"] = invocationId;

                Dictionary <string, string> environmentVariables = new Dictionary <string, string>();

                string functionInstanceOutputPath = Path.Combine(Path.GetTempPath(), "Functions", "Binding", invocationId);
                await ProcessInputBindingsAsync(convertedInput, functionInstanceOutputPath, binder, _inputBindings, _outputBindings, bindingData, environmentVariables);

                InitializeEnvironmentVariables(environmentVariables, functionInstanceOutputPath, input, _outputBindings, functionExecutionContext);

                PSDataCollection <ErrorRecord> errors = await InvokePowerShellScript(environmentVariables, traceWriter);

                await ProcessOutputBindingsAsync(functionInstanceOutputPath, _outputBindings, input, binder, bindingData);

                if (errors.Any())
                {
                    ErrorRecord error = errors.FirstOrDefault();
                    if (error != null)
                    {
                        throw new RuntimeException("PowerShell script error", error.Exception, error);
                    }
                }
                else
                {
                    TraceWriter.Info(string.Format("Function completed (Success, Id={0})", invocationId));
                }
            }
            catch (Exception)
            {
                startedEvent.Success = false;
                TraceWriter.Error(string.Format("Function completed (Failure, Id={0})", invocationId));
                throw;
            }
            finally
            {
                _metrics.EndEvent(startedEvent);
            }
        }
Exemple #10
0
        // Called on success and failure
        public void End(bool success)
        {
            _startedEvent.Success = success;

            string eventName    = success ? MetricEventNames.FunctionInvokeSucceeded : MetricEventNames.FunctionInvokeFailed;
            string functionName = _metadata != null ? _metadata.Name : string.Empty;
            string data         = string.Format(Properties.Resources.FunctionInvocationMetricsData, _startedEvent.FunctionMetadata.Language, functionName, success, Stopwatch.IsHighResolution);

            _metrics.LogEvent(eventName, _startedEvent.FunctionName, data);

            _startedEvent.Data = data;
            _metrics.EndEvent(_startedEvent);

            if (_invokeLatencyEvent is MetricEvent metricEvent)
            {
                metricEvent.Data = data;
            }

            _metrics.EndEvent(_invokeLatencyEvent);
        }
Exemple #11
0
        public override async Task Invoke(object[] parameters)
        {
            object           input       = parameters[0];
            TraceWriter      traceWriter = (TraceWriter)parameters[1];
            IBinderEx        binder      = (IBinderEx)parameters[2];
            ExecutionContext functionExecutionContext = (ExecutionContext)parameters[3];
            string           invocationId             = functionExecutionContext.InvocationId.ToString();

            FunctionStartedEvent startedEvent = new FunctionStartedEvent(functionExecutionContext.InvocationId, Metadata);

            _metrics.BeginEvent(startedEvent);

            try
            {
                TraceWriter.Verbose(string.Format("Function started (Id={0})", invocationId));

                var scriptExecutionContext = CreateScriptExecutionContext(input, traceWriter, TraceWriter, functionExecutionContext);

                Dictionary <string, string> bindingData = GetBindingData(input, binder, _inputBindings, _outputBindings);
                bindingData["InvocationId"]           = invocationId;
                scriptExecutionContext["bindingData"] = bindingData;

                await ProcessInputBindingsAsync(binder, scriptExecutionContext, bindingData);

                object functionResult = await ScriptFunc(scriptExecutionContext);

                await ProcessOutputBindingsAsync(_outputBindings, input, binder, bindingData, scriptExecutionContext, functionResult);

                TraceWriter.Verbose(string.Format("Function completed (Success, Id={0})", invocationId));
            }
            catch
            {
                startedEvent.Success = false;
                TraceWriter.Verbose(string.Format("Function completed (Failure, Id={0})", invocationId));
                throw;
            }
            finally
            {
                _metrics.EndEvent(startedEvent);
            }
        }
Exemple #12
0
        public async Task Invoke(object[] parameters)
        {
            // We require the ExecutionContext, so this will throw if one is not found.
            ExecutionContext functionExecutionContext = parameters.OfType <ExecutionContext>().First();

            PopulateExecutionContext(functionExecutionContext);

            // These may not be present, so null is okay.
            TraceWriter functionTraceWriter = parameters.OfType <TraceWriter>().FirstOrDefault();
            Binder      binder       = parameters.OfType <Binder>().FirstOrDefault();
            ILogger     logger       = parameters.OfType <ILogger>().FirstOrDefault();
            string      invocationId = functionExecutionContext.InvocationId.ToString();

            var startedEvent = new FunctionStartedEvent(functionExecutionContext.InvocationId, Metadata);

            _metrics.BeginEvent(startedEvent);
            var invokeLatencyEvent  = LogInvocationMetrics(_metrics, Metadata);
            var invocationStopWatch = new Stopwatch();

            invocationStopWatch.Start();

            try
            {
                string startMessage = $"Function started (Id={invocationId})";
                TraceWriter.Info(startMessage);
                Logger?.LogInformation(startMessage);

                FunctionInvocationContext context = new FunctionInvocationContext
                {
                    ExecutionContext = functionExecutionContext,
                    Binder           = binder,
                    TraceWriter      = functionTraceWriter,
                    Logger           = logger
                };

                await InvokeCore(parameters, context);

                invocationStopWatch.Stop();
                LogFunctionResult(startedEvent, true, invocationId, invocationStopWatch.ElapsedMilliseconds);
            }
            catch (AggregateException ex)
            {
                ExceptionDispatchInfo exInfo = null;

                // If there's only a single exception, rethrow it by itself
                Exception singleEx = ex.Flatten().InnerExceptions.SingleOrDefault();
                if (singleEx != null)
                {
                    exInfo = ExceptionDispatchInfo.Capture(singleEx);
                }
                else
                {
                    exInfo = ExceptionDispatchInfo.Capture(ex);
                }

                invocationStopWatch.Stop();
                LogFunctionResult(startedEvent, false, invocationId, invocationStopWatch.ElapsedMilliseconds);
                exInfo.Throw();
            }
            catch
            {
                invocationStopWatch.Stop();
                LogFunctionResult(startedEvent, false, invocationId, invocationStopWatch.ElapsedMilliseconds);
                throw;
            }
            finally
            {
                if (startedEvent != null)
                {
                    _metrics.EndEvent(startedEvent);
                }
                if (invokeLatencyEvent != null)
                {
                    _metrics.EndEvent(invokeLatencyEvent);
                }
            }
        }
        public override async Task Invoke(object[] parameters)
        {
            FunctionStartedEvent startedEvent = null;
            string invocationId = null;

            try
            {
                // Separate system parameters from the actual method parameters
                object[]   originalParameters = parameters;
                MethodInfo function           = await GetFunctionTargetAsync();

                int      actualParameterCount = function.GetParameters().Length;
                object[] systemParameters     = parameters.Skip(actualParameterCount).ToArray();
                parameters = parameters.Take(actualParameterCount).ToArray();

                ExecutionContext functionExecutionContext = (ExecutionContext)systemParameters[0];
                invocationId = functionExecutionContext.InvocationId.ToString();

                startedEvent = new FunctionStartedEvent(functionExecutionContext.InvocationId, Metadata);
                _metrics.BeginEvent(startedEvent);

                TraceWriter.Info(string.Format("Function started (Id={0})", invocationId));

                parameters = ProcessInputParameters(parameters);

                object functionResult = function.Invoke(null, parameters);

                // after the function executes, we have to copy values back into the original
                // array to ensure object references are maintained (since we took a copy above)
                for (int i = 0; i < parameters.Length; i++)
                {
                    originalParameters[i] = parameters[i];
                }

                if (functionResult is Task)
                {
                    functionResult = await((Task)functionResult).ContinueWith(t => GetTaskResult(t));
                }

                if (functionResult != null)
                {
                    _resultProcessor(function, parameters, systemParameters, functionResult);
                }

                TraceWriter.Info(string.Format("Function completed (Success, Id={0})", invocationId));
            }
            catch
            {
                if (startedEvent != null)
                {
                    startedEvent.Success = false;
                    TraceWriter.Error(string.Format("Function completed (Failure, Id={0})", invocationId));
                }
                else
                {
                    TraceWriter.Error("Function completed (Failure)");
                }
                throw;
            }
            finally
            {
                if (startedEvent != null)
                {
                    _metrics.EndEvent(startedEvent);
                }
            }
        }
Exemple #14
0
 public void EndEvent(MetricEvent metricEvent)
 {
     _metricsLogger.EndEvent(metricEvent);
 }
Exemple #15
0
        internal async Task ExecuteScriptAsync(string path, string arguments, object[] invocationParameters)
        {
            object           input       = invocationParameters[0];
            TraceWriter      traceWriter = (TraceWriter)invocationParameters[1];
            Binder           binder      = (Binder)invocationParameters[2];
            ExecutionContext functionExecutionContext = (ExecutionContext)invocationParameters[3];
            string           invocationId             = functionExecutionContext.InvocationId.ToString();

            FunctionStartedEvent startedEvent = new FunctionStartedEvent(functionExecutionContext.InvocationId, Metadata);

            _metrics.BeginEvent(startedEvent);

            try
            {
                TraceWriter.Info(string.Format("Function started (Id={0})", invocationId));

                string workingDirectory           = Path.GetDirectoryName(_scriptFilePath);
                string functionInstanceOutputPath = Path.Combine(Path.GetTempPath(), "Functions", "Binding", invocationId);

                Dictionary <string, string> environmentVariables = new Dictionary <string, string>();
                InitializeEnvironmentVariables(environmentVariables, functionInstanceOutputPath, input, _outputBindings, functionExecutionContext);

                object convertedInput = ConvertInput(input);
                ApplyBindingData(convertedInput, binder);
                Dictionary <string, object> bindingData = binder.BindingData;
                bindingData["InvocationId"] = invocationId;

                await ProcessInputBindingsAsync(convertedInput, functionInstanceOutputPath, binder, _inputBindings, _outputBindings, bindingData, environmentVariables);

                // TODO
                // - put a timeout on how long we wait?
                // - need to periodically flush the standard out to the TraceWriter
                Process process = CreateProcess(path, workingDirectory, arguments, environmentVariables);
                process.Start();
                process.WaitForExit();

                string output = process.StandardOutput.ReadToEnd();
                TraceWriter.Info(output);
                traceWriter.Info(output);

                startedEvent.Success = process.ExitCode == 0;

                if (!startedEvent.Success)
                {
                    string error = process.StandardError.ReadToEnd();
                    throw new ApplicationException(error);
                }

                await ProcessOutputBindingsAsync(functionInstanceOutputPath, _outputBindings, input, binder, bindingData);

                TraceWriter.Info(string.Format("Function completed (Success, Id={0})", invocationId));
            }
            catch
            {
                startedEvent.Success = false;
                TraceWriter.Error(string.Format("Function completed (Failure, Id={0})", invocationId));
                throw;
            }
            finally
            {
                _metrics.EndEvent(startedEvent);
            }
        }
        public async Task Invoke(object[] parameters)
        {
            // We require the ExecutionContext, so this will throw if one is not found.
            ExecutionContext functionExecutionContext = parameters.OfType <ExecutionContext>().First();

            // These may not be present, so null is okay.
            TraceWriter functionTraceWriter = parameters.OfType <TraceWriter>().FirstOrDefault();
            Binder      binder = parameters.OfType <Binder>().FirstOrDefault();

            string invocationId = functionExecutionContext.InvocationId.ToString();

            FunctionStartedEvent startedEvent = new FunctionStartedEvent(functionExecutionContext.InvocationId, Metadata);

            _metrics.BeginEvent(startedEvent);

            LogInvocationMetrics(_metrics, Metadata.Bindings);

            try
            {
                TraceWriter.Info($"Function started (Id={invocationId})");

                FunctionInvocationContext context = new FunctionInvocationContext
                {
                    ExecutionContext = functionExecutionContext,
                    Binder           = binder,
                    TraceWriter      = functionTraceWriter
                };

                await InvokeCore(parameters, context);

                TraceWriter.Info($"Function completed (Success, Id={invocationId})");
            }
            catch (AggregateException ex)
            {
                ExceptionDispatchInfo exInfo = null;

                // If there's only a single exception, rethrow it by itself
                Exception singleEx = ex.Flatten().InnerExceptions.SingleOrDefault();
                if (singleEx != null)
                {
                    exInfo = ExceptionDispatchInfo.Capture(singleEx);
                }
                else
                {
                    exInfo = ExceptionDispatchInfo.Capture(ex);
                }

                LogFunctionFailed(startedEvent, "Failure", invocationId);
                exInfo.Throw();
            }
            catch
            {
                LogFunctionFailed(startedEvent, "Failure", invocationId);
                throw;
            }
            finally
            {
                if (startedEvent != null)
                {
                    _metrics.EndEvent(startedEvent);
                }
            }
        }
Exemple #17
0
        internal async Task ExecuteScriptAsync(string path, string arguments, object[] invocationParameters)
        {
            object           input       = invocationParameters[0];
            TraceWriter      traceWriter = (TraceWriter)invocationParameters[1];
            IBinderEx        binder      = (IBinderEx)invocationParameters[2];
            ExecutionContext functionExecutionContext = (ExecutionContext)invocationParameters[3];
            string           invocationId             = functionExecutionContext.InvocationId.ToString();

            FunctionStartedEvent startedEvent = new FunctionStartedEvent(functionExecutionContext.InvocationId, Metadata);

            _metrics.BeginEvent(startedEvent);

            // perform any required input conversions
            object convertedInput = input;

            if (input != null)
            {
                HttpRequestMessage request = input as HttpRequestMessage;
                if (request != null)
                {
                    // TODO: Handle other content types? (E.g. byte[])
                    if (request.Content != null && request.Content.Headers.ContentLength > 0)
                    {
                        convertedInput = ((HttpRequestMessage)input).Content.ReadAsStringAsync().Result;
                    }
                }
            }

            TraceWriter.Info(string.Format("Function started (Id={0})", invocationId));

            string workingDirectory           = Path.GetDirectoryName(_scriptFilePath);
            string functionInstanceOutputPath = Path.Combine(Path.GetTempPath(), "Functions", "Binding", invocationId);

            Dictionary <string, string> environmentVariables = new Dictionary <string, string>();

            InitializeEnvironmentVariables(environmentVariables, functionInstanceOutputPath, input, _outputBindings, functionExecutionContext);

            Dictionary <string, string> bindingData = GetBindingData(convertedInput, binder);

            bindingData["InvocationId"] = invocationId;

            await ProcessInputBindingsAsync(convertedInput, functionInstanceOutputPath, binder, bindingData, environmentVariables);

            // TODO
            // - put a timeout on how long we wait?
            // - need to periodically flush the standard out to the TraceWriter
            Process process = CreateProcess(path, workingDirectory, arguments, environmentVariables);

            process.Start();
            process.WaitForExit();

            bool failed = process.ExitCode != 0;

            startedEvent.Success = !failed;
            _metrics.EndEvent(startedEvent);

            if (failed)
            {
                startedEvent.Success = false;

                TraceWriter.Error(string.Format("Function completed (Failure, Id={0})", invocationId));

                string error = process.StandardError.ReadToEnd();
                throw new ApplicationException(error);
            }

            string output = process.StandardOutput.ReadToEnd();

            TraceWriter.Info(output);
            traceWriter.Info(output);

            await ProcessOutputBindingsAsync(functionInstanceOutputPath, _outputBindings, input, binder, bindingData);

            TraceWriter.Info(string.Format("Function completed (Success, Id={0})", invocationId));
        }