public static void FunctionStarted(FunctionStartedEvent startedEvent)
 {
     lock (functionActivityTrackerLockObject)
     {
         if (instance == null)
         {
             instance = new FunctionActivityTracker();
         }
         instance.FunctionStarted(startedEvent);
     }
 }
 public static void FunctionCompleted(FunctionStartedEvent completedEvent)
 {
     lock (functionActivityTrackerLockObject)
     {
         if (instance != null)
         {
             instance.FunctionCompleted(completedEvent);
             if (!instance.IsActive)
             {
                 instance.StopEtwTaskAndRaiseFinishedEvent();
                 instance = null;
             }
         }
     }
 }
            internal void FunctionCompleted(FunctionStartedEvent functionStartedEvent)
            {
                var functionStage = (functionStartedEvent.Success == false) ? ExecutionStage.Failed : ExecutionStage.Succeeded;
                long executionTimeInMS = (long)functionStartedEvent.Duration.TotalMilliseconds;

                var monitoringEvent = new FunctionMetrics(functionStartedEvent.FunctionMetadata.Name, functionStage, executionTimeInMS);
                _functionMetricsQueue.Enqueue(monitoringEvent);
                var key = GetDictionaryKey(functionStartedEvent.FunctionMetadata.Name, functionStartedEvent.InvocationId);
                if (_runningFunctions.ContainsKey(key))
                {
                    lock (_functionMetricEventLockObject)
                    {
                        if (_runningFunctions.ContainsKey(key))
                        {
                            var functionInfo = _runningFunctions[key];
                            functionInfo.ExecutionStage = ExecutionStage.Finished;
                            functionInfo.Success = functionStartedEvent.Success;

                            var endTime = functionStartedEvent.Timestamp + functionStartedEvent.Duration;
                            functionInfo.EndTime = functionStartedEvent.Timestamp + functionStartedEvent.Duration;

                            RaiseFunctionMetricEvent(functionInfo, _runningFunctions.Keys.Count, endTime);
                            _runningFunctions.Remove(key);
                        }
                    }
                }
            }
            internal void FunctionStarted(FunctionStartedEvent startedEvent)
            {
                _totalExecutionCount++;

                var metricEventPerFunction = new FunctionMetrics(startedEvent.FunctionMetadata.Name, ExecutionStage.Started, 0);
                _functionMetricsQueue.Enqueue(metricEventPerFunction);
                var key = GetDictionaryKey(startedEvent.FunctionMetadata.Name, startedEvent.InvocationId);
                if (!_runningFunctions.ContainsKey(key))
                {
                    lock (_functionMetricEventLockObject)
                    {
                        if (!_runningFunctions.ContainsKey(key))
                        {
                            _runningFunctions.Add(key, new RunningFunctionInfo(startedEvent.FunctionMetadata.Name, startedEvent.InvocationId, startedEvent.Timestamp, startedEvent.Success));
                        }
                    }
                }
            }
 internal void FunctionStarted(FunctionStartedEvent startedEvent)
 {
     lock (_functionActivityTrackerLockObject)
     {
         if (instance == null)
         {
             instance = new FunctionActivityTracker(_eventGenerator, _functionActivityFlushIntervalSeconds);
         }
         instance.FunctionStarted(startedEvent);
     }
 }
        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.Verbose(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.Verbose(string.Format("Function completed (Success, Id={0})", invocationId));
            }
            catch
            {
                if (startedEvent != null)
                {
                    startedEvent.Success = false;
                    TraceWriter.Verbose(string.Format("Function completed (Failure, Id={0})", invocationId));
                }
                else
                {
                    TraceWriter.Verbose("Function completed (Failure)");
                }
                throw;
            }
            finally
            {
                if (startedEvent != null)
                {
                    _metrics.EndEvent(startedEvent);
                }
            }
        }
        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);
            }
        }
        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.Verbose(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, _inputBindings, _outputBindings);
            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.Verbose(string.Format("Function completed (Failure, Id={0})", invocationId));

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

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

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

            TraceWriter.Verbose(string.Format("Function completed (Success, Id={0})", invocationId));
        }
        private void LogFunctionFailed(FunctionStartedEvent startedEvent, string resultString, string invocationId)
        {
            if (startedEvent != null)
            {
                startedEvent.Success = false;
            }

            TraceWriter.Error($"Function completed ({resultString}, Id={invocationId ?? "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();

            // 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);
                }
            }
        }
            internal void FunctionCompleted(FunctionStartedEvent completedEvent)
            {
                if (runningFunctionCount > 0)
                {
                    runningFunctionCount--;
                }

                var functionStage = (completedEvent.Success == false) ? ExecutionStage.Failed : ExecutionStage.Succeeded;
                long executionTimeInMS = (long)completedEvent.EndTime.Subtract(completedEvent.StartTime).TotalMilliseconds;

                var monitoringEvent = new FunctionMetrics(completedEvent.FunctionMetadata.Name, functionStage, executionTimeInMS);
                functionMetricsQueue.Enqueue(monitoringEvent);
            }
            internal void FunctionStarted(FunctionStartedEvent startedEvent)
            {
                totalExecutionCount++;
                runningFunctionCount++;

                var metricEventPerFunction = new FunctionMetrics(startedEvent.FunctionMetadata.Name, ExecutionStage.Started, 0);
                functionMetricsQueue.Enqueue(metricEventPerFunction);
            }