private CodeMemberMethod CreateRecordMetricMethodByDataClass()

in telemetry/csharp/AwsToolkit.Telemetry.Events.Generator.Core/DefinitionsBuilder.cs [355:576]


        private CodeMemberMethod CreateRecordMetricMethodByDataClass(Metric metric)
        {
            CodeMemberMethod recordMethod = new CodeMemberMethod
            {
                Attributes = MemberAttributes.Public | MemberAttributes.Static,
                Name = $"Record{SanitizeName(metric.name)}",
                ReturnType = new CodeTypeReference()
            };

            if (!string.IsNullOrWhiteSpace(metric.description))
            {
                recordMethod.Comments.Add(new CodeCommentStatement("Records Telemetry Event:", true));
                recordMethod.Comments.Add(new CodeCommentStatement(metric.description, true));
            }

            // RecordXxx Parameters
            var telemetryLogger = new CodeParameterDeclarationExpression("this ITelemetryLogger", "telemetryLogger");
            recordMethod.Parameters.Add(telemetryLogger);
            recordMethod.Parameters.Add(new CodeParameterDeclarationExpression(SanitizeName(metric.name), "payload"));
            recordMethod.Parameters.Add(new CodeParameterDeclarationExpression("Func<MetricDatum, MetricDatum>", "transformDatum = null"));

            // Generate method body
            var tryStatements = new List<CodeStatement>();
            var catchClauses = new List<CodeCatchClause>();

            // Create a metrics object from the given payload
            // Generate the method body
            var metrics = new CodeVariableReferenceExpression("metrics");
            var metricsDataField = new CodeFieldReferenceExpression(metrics, "Data");
            var payload = new CodeArgumentReferenceExpression("payload");
            var transformDatum = new CodeArgumentReferenceExpression("transformDatum");
            var datum = new CodeVariableReferenceExpression("datum");
            var datumAddData = new CodeMethodReferenceExpression(datum, AddMetadataMethodName);
            var datetimeNow = new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(DateTime)), nameof(DateTime.Now));

            // Instantiate metrics
            tryStatements.Add(new CodeVariableDeclarationStatement("var", metrics.VariableName, new CodeObjectCreateExpression("Metrics")));

            // Set metrics.CreatedOn to (payload.CreatedOn ?? DateTime.Now)
            var payloadCreatedOn = new CodeFieldReferenceExpression(payload, "CreatedOn");
            var metricsCreatedOn = new CodeFieldReferenceExpression(metrics, "CreatedOn");

            var createdOnCond = new CodeConditionStatement();
            createdOnCond.Condition = new CodeFieldReferenceExpression(payloadCreatedOn, "HasValue");
            createdOnCond.TrueStatements.Add(new CodeAssignStatement(metricsCreatedOn, new CodeFieldReferenceExpression(payloadCreatedOn, "Value")));
            createdOnCond.FalseStatements.Add(new CodeAssignStatement(metricsCreatedOn, datetimeNow));
            tryStatements.Add(createdOnCond);

            // Instantiate a Data list
            tryStatements.Add(new CodeAssignStatement(metricsDataField, new CodeObjectCreateExpression($"List<{MetricDatumFullName}>")));
            
            // Instantiate MetricDatum
            tryStatements.Add(new CodeSnippetStatement());
            tryStatements.Add(new CodeVariableDeclarationStatement("var", datum.VariableName, new CodeObjectCreateExpression(MetricDatumFullName)));
            tryStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(datum, "MetricName"), new CodePrimitiveExpression(metric.name)));
            tryStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(datum, "Unit"), GetMetricUnitExpression(metric)));
            tryStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(datum, "Passive"), new CodeFieldReferenceExpression(payload, "Passive")));
            tryStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(datum, "TrackPerformance"), new CodeFieldReferenceExpression(payload, "TrackPerformance")));

            // Set Datum.Value to (payload.Value ?? 1)
            var payloadValue = new CodeFieldReferenceExpression(payload, "Value");
            var datumValue = new CodeFieldReferenceExpression(datum, "Value");

            var valueCond = new CodeConditionStatement();
            valueCond.Condition = new CodeFieldReferenceExpression(payloadValue, "HasValue");
            valueCond.TrueStatements.Add(new CodeAssignStatement(datumValue, new CodeFieldReferenceExpression(payloadValue, "Value")));
            valueCond.FalseStatements.Add(new CodeAssignStatement(datumValue, new CodePrimitiveExpression(1)));
            tryStatements.Add(valueCond);

            // Generate: datum.AddMetadata("awsAccount", payload.AwsAccount);
            var payloadAwsAccount = new CodeFieldReferenceExpression(payload, "AwsAccount");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("awsAccount"), payloadAwsAccount)));

            // Generate: datum.AddMetadata("awsRegion", payload.AwsRegion);
            var payloadAwsRegion = new CodeFieldReferenceExpression(payload, "AwsRegion");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("awsRegion"), payloadAwsRegion)));

            // Generate: datum.AddMetadata("reason", payload.Reason);
            var payloadReason = new CodeFieldReferenceExpression(payload, "Reason");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("reason"), payloadReason)));

            // Generate: datum.AddMetadata("reasonDesc", payload.ReasonDescription);
            var payloadReasonDescription = new CodeFieldReferenceExpression(payload, "ReasonDescription");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("reasonDesc"), payloadReasonDescription)));

            // Generate: datum.AddMetadata("source", payload.Source);
            var payloadSource = new CodeFieldReferenceExpression(payload, "Source");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("source"), payloadSource)));

            // Generate: datum.AddMetadata("errorCode", payload.ErrorCode);
            var payloadErrorCode = new CodeFieldReferenceExpression(payload, "ErrorCode");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("errorCode"), payloadErrorCode)));

            // Generate: datum.AddMetadata("causedBy", payload.CausedBy);
            var payloadCausedBy = new CodeFieldReferenceExpression(payload, "CausedBy");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("causedBy"), payloadCausedBy)));

            // Generate: datum.AddMetadata("httpStatusCode", payload.HttpStatusCode);
            var payloadHttpStatusCode = new CodeFieldReferenceExpression(payload, "HttpStatusCode");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("httpStatusCode"), payloadHttpStatusCode)));

            // Generate: datum.AddMetadata("requestId", payload.RequestId);
            var payloadRequestId = new CodeFieldReferenceExpression(payload, "RequestId");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("requestId"), payloadRequestId)));

            // Generate: datum.AddMetadata("requestServiceType", payload.RequestServiceType);
            var payloadRequestServiceType = new CodeFieldReferenceExpression(payload, "RequestServiceType");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("requestServiceType"), payloadRequestServiceType)));

            // Generate: datum.AddMetadata("traceId", payload.TraceId);
            var payloadTraceId = new CodeFieldReferenceExpression(payload, "TraceId");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("traceId"), payloadTraceId)));
            
            // Generate: datum.AddMetadata("metricId", payload.MetricId);
            var payloadMetricId = new CodeFieldReferenceExpression(payload, "MetricId");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("metricId"), payloadMetricId)));
            
            // Generate: datum.AddMetadata("parentId", payload.ParentId);
            var payloadParentId = new CodeFieldReferenceExpression(payload, "ParentId");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("parentId"), payloadParentId)));
            
            // Generate: 
            // if (payload.Duration.HasValue)
            // {
            //     datum.AddMetadata("duration", payload.Duration.Value);
            // }
            var payloadDuration= new CodeFieldReferenceExpression(payload, "Duration");
            var hasValueDuration = new CodeFieldReferenceExpression(payloadDuration, "HasValue");
            var durationMetadata = new CodeMethodInvokeExpression(datumAddData,
                        new CodePrimitiveExpression("duration"), new CodeFieldReferenceExpression(payloadDuration, "Value"));

            tryStatements.Add(new CodeConditionStatement(hasValueDuration, new CodeExpressionStatement(durationMetadata)));

            // Generate: datum.AddMetadata("locale", payload.Locale);
            var payloadLocale = new CodeFieldReferenceExpression(payload, "Locale");
            tryStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(datumAddData,
                new CodePrimitiveExpression("locale"), payloadLocale)));

            // Set MetricDatum Metadata values
            metric.metadata?
                .Where(metadata => !ImplicitFields.Contains(metadata.type))
                .ToList().ForEach(metadata =>
            {
                tryStatements.Add(new CodeSnippetStatement());

                var payloadField = new CodeFieldReferenceExpression(payload, SanitizeName(metadata.type));

                if (IsNullable(metadata))
                {
                    // Generate: 
                    // if (payload.foo.HasValue)
                    // {
                    //     datum.AddMetadata("foo", payload.foo.Value);
                    // }
                    var hasValue = new CodeFieldReferenceExpression(payloadField, "HasValue");
                    var addMetadata = new CodeMethodInvokeExpression(datumAddData,
                        new CodePrimitiveExpression(metadata.type), new CodeFieldReferenceExpression(payloadField, "Value"));

                    tryStatements.Add(
                        new CodeConditionStatement(hasValue, new CodeExpressionStatement(addMetadata)));
                }
                else
                {
                    // Generate: datum.AddMetadata("foo", payload.foo);
                    tryStatements.Add(new CodeExpressionStatement (new CodeMethodInvokeExpression(datumAddData,
                        new CodePrimitiveExpression(metadata.type), payloadField)));
                }
            });

            // Generate: "InvokeTransform function on datum"
            // datum = datum.InvokeTransform(transformDatum) 
            var datumInvoke = new CodeMethodReferenceExpression(datum, InvokeTransformMethodName);
            var invokeTransform = new CodeMethodInvokeExpression(datumInvoke, transformDatum);
            var assignTransform = new CodeAssignStatement(datum, invokeTransform);
            tryStatements.Add(new CodeSnippetStatement());
            tryStatements.Add(assignTransform);

            // Generate: metrics.Data.Add(datum);
            tryStatements.Add(new CodeSnippetStatement());
            tryStatements.Add(new CodeExpressionStatement (new CodeMethodInvokeExpression(metricsDataField, "Add", datum)));

            // Generate: telemetryLogger.Record(metrics);
            tryStatements.Add(new CodeExpressionStatement (new CodeMethodInvokeExpression(new CodeArgumentReferenceExpression("telemetryLogger"), "Record", metrics)));

            var catchClause = new CodeCatchClause("e", new CodeTypeReference(typeof(Exception)));
            catchClause.Statements.Add(new CodeExpressionStatement(
                new CodeMethodInvokeExpression(
                    new CodeFieldReferenceExpression(new CodeArgumentReferenceExpression("telemetryLogger"), "Logger"),
                    "Error",
                    new CodePrimitiveExpression("Error recording telemetry event"),
                    new CodeArgumentReferenceExpression("e"))
            ));

            // System.Diagnostics.Debug.Assert(false, "Error Recording Telemetry");
            catchClause.Statements.Add(new CodeExpressionStatement(
                new CodeMethodInvokeExpression(
                    _debugAssert,
                    new CodePrimitiveExpression(false),
                    new CodePrimitiveExpression("Error Recording Telemetry"))
            ));

            catchClauses.Add(catchClause);

            recordMethod.Statements.Add(
                new CodeTryCatchFinallyStatement(tryStatements.ToArray(), catchClauses.ToArray())
            );

            return recordMethod;
        }