private CodeMemberMethod CreateRecordMetricMethodByDataClass()

in telemetry/csharp/AwsToolkit.Telemetry.Events.Generator/DefinitionsBuilder.cs [315:452]


        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"));

            // 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 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")));

            // 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)));


            // Set MetricDatum Metadata values
            metric.metadata?.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: 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;
        }