"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.spanToTelemetryContract = spanToTelemetryContract;
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
var url_1 = require("url");
var api_1 = require("@opentelemetry/api");
var semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
var Constants = __importStar(require("../../Declarations/Constants"));
var EventHub_1 = require("./Azure/EventHub");
var Util = require("../../Library/Util");
function createPropertiesFromSpan(span) {
    var properties = {};
    for (var _i = 0, _a = Object.keys(span.attributes); _i < _a.length; _i++) {
        var key = _a[_i];
        if (!(key.startsWith("http.") ||
            key.startsWith("rpc.") ||
            key.startsWith("db.") ||
            key.startsWith("peer.") ||
            key.startsWith("net."))) {
            properties[key] = span.attributes[key];
        }
    }
    var links = span.links.map(function (link) { return ({
        operation_Id: link.context.traceId,
        id: link.context.spanId
    }); });
    if (links.length > 0) {
        properties["_MS.links"] = Util.stringify(links);
    }
    return properties;
}
function isSqlDB(dbSystem) {
    return (dbSystem === semantic_conventions_1.DbSystemValues.DB2 ||
        dbSystem === semantic_conventions_1.DbSystemValues.DERBY ||
        dbSystem === semantic_conventions_1.DbSystemValues.MARIADB ||
        dbSystem === semantic_conventions_1.DbSystemValues.MSSQL ||
        dbSystem === semantic_conventions_1.DbSystemValues.ORACLE ||
        dbSystem === semantic_conventions_1.DbSystemValues.SQLITE ||
        dbSystem === semantic_conventions_1.DbSystemValues.OTHER_SQL ||
        dbSystem === semantic_conventions_1.DbSystemValues.HSQLDB ||
        dbSystem === semantic_conventions_1.DbSystemValues.H2);
}
function getUrl(span) {
    var httpMethod = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_METHOD];
    if (httpMethod) {
        var httpUrl = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_URL];
        if (httpUrl) {
            return String(httpUrl);
        }
        else {
            var httpScheme = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_SCHEME];
            var httpTarget = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_TARGET];
            if (httpScheme && httpTarget) {
                var httpHost = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_HOST];
                if (httpHost) {
                    return "".concat(httpScheme, "://").concat(httpHost).concat(httpTarget);
                }
                else {
                    var netPeerPort = span.attributes[semantic_conventions_1.SemanticAttributes.NET_PEER_PORT];
                    if (netPeerPort) {
                        var netPeerName = span.attributes[semantic_conventions_1.SemanticAttributes.NET_PEER_NAME];
                        if (netPeerName) {
                            return "".concat(httpScheme, "://").concat(netPeerName, ":").concat(netPeerPort).concat(httpTarget);
                        }
                        else {
                            var netPeerIp = span.attributes[semantic_conventions_1.SemanticAttributes.NET_PEER_IP];
                            if (netPeerIp) {
                                return "".concat(httpScheme, "://").concat(netPeerIp, ":").concat(netPeerPort).concat(httpTarget);
                            }
                        }
                    }
                }
            }
        }
    }
    return "";
}
function getDependencyTarget(span) {
    var peerService = span.attributes[semantic_conventions_1.SemanticAttributes.PEER_SERVICE];
    var httpHost = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_HOST];
    var httpUrl = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_URL];
    var netPeerName = span.attributes[semantic_conventions_1.SemanticAttributes.NET_PEER_NAME];
    var netPeerIp = span.attributes[semantic_conventions_1.SemanticAttributes.NET_PEER_IP];
    if (peerService) {
        return String(peerService);
    }
    else if (httpHost) {
        return String(httpHost);
    }
    else if (httpUrl) {
        return String(httpUrl);
    }
    else if (netPeerName) {
        return String(netPeerName);
    }
    else if (netPeerIp) {
        return String(netPeerIp);
    }
    return "";
}
function createDependencyData(span) {
    var remoteDependency = {
        name: span.name,
        success: span.status.code != api_1.SpanStatusCode.ERROR,
        resultCode: "0",
        duration: 0,
        data: "",
        dependencyTypeName: ""
    };
    if (span.kind === api_1.SpanKind.PRODUCER) {
        remoteDependency.dependencyTypeName = Constants.DependencyTypeName.QueueMessage;
    }
    if (span.kind === api_1.SpanKind.INTERNAL && span.parentSpanId) {
        remoteDependency.dependencyTypeName = Constants.DependencyTypeName.InProc;
    }
    var httpMethod = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_METHOD];
    var dbSystem = span.attributes[semantic_conventions_1.SemanticAttributes.DB_SYSTEM];
    var rpcSystem = span.attributes[semantic_conventions_1.SemanticAttributes.RPC_SYSTEM];
    // HTTP Dependency
    if (httpMethod) {
        remoteDependency.dependencyTypeName = Constants.DependencyTypeName.Http;
        var httpUrl = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_URL];
        if (httpUrl) {
            var pathName = "";
            try {
                var dependencyUrl = new url_1.URL(String(httpUrl));
                pathName = dependencyUrl.pathname;
            }
            catch (ex) {
                // Ignore error
            }
            remoteDependency.name = "".concat(httpMethod, " ").concat(pathName);
        }
        remoteDependency.data = getUrl(span);
        var httpStatusCode = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_STATUS_CODE];
        if (httpStatusCode) {
            remoteDependency.resultCode = String(httpStatusCode);
        }
        var target = getDependencyTarget(span);
        if (target) {
            try {
                // Remove default port
                var portRegex = new RegExp(/(https?)(:\/\/.*)(:\d+)(\S*)/);
                var res = portRegex.exec(target);
                if (res != null) {
                    var protocol = res[1];
                    var port = res[3];
                    if ((protocol == "https" && port == ":443") || (protocol == "http" && port == ":80")) {
                        // Drop port
                        target = res[1] + res[2] + res[4];
                    }
                }
            }
            catch (error) {
                // Ignore error
            }
            remoteDependency.target = "".concat(target);
        }
    }
    // DB Dependency
    else if (dbSystem) {
        // TODO: Remove special logic when Azure UX supports OpenTelemetry dbSystem
        if (String(dbSystem) === semantic_conventions_1.DbSystemValues.MYSQL) {
            remoteDependency.dependencyTypeName = "mysql";
        }
        else if (String(dbSystem) === semantic_conventions_1.DbSystemValues.POSTGRESQL) {
            remoteDependency.dependencyTypeName = "postgresql";
        }
        else if (String(dbSystem) === semantic_conventions_1.DbSystemValues.MONGODB) {
            remoteDependency.dependencyTypeName = "mongodb";
        }
        else if (String(dbSystem) === semantic_conventions_1.DbSystemValues.REDIS) {
            remoteDependency.dependencyTypeName = "redis";
        }
        else if (isSqlDB(String(dbSystem))) {
            remoteDependency.dependencyTypeName = "SQL";
        }
        else {
            remoteDependency.dependencyTypeName = String(dbSystem);
        }
        var dbStatement = span.attributes[semantic_conventions_1.SemanticAttributes.DB_STATEMENT];
        var dbOperation = span.attributes[semantic_conventions_1.SemanticAttributes.DB_OPERATION];
        if (dbStatement) {
            remoteDependency.data = String(dbStatement);
        }
        else if (dbOperation) {
            remoteDependency.data = String(dbOperation);
        }
        var target = getDependencyTarget(span);
        var dbName = span.attributes[semantic_conventions_1.SemanticAttributes.DB_NAME];
        if (target) {
            remoteDependency.target = dbName ? "".concat(target, "|").concat(dbName) : "".concat(target);
        }
        else {
            remoteDependency.target = dbName ? "".concat(dbName) : "".concat(dbSystem);
        }
    }
    // grpc Dependency
    else if (rpcSystem) {
        remoteDependency.dependencyTypeName = Constants.DependencyTypeName.Grpc;
        var grpcStatusCode = span.attributes[semantic_conventions_1.SemanticAttributes.RPC_GRPC_STATUS_CODE];
        if (grpcStatusCode) {
            remoteDependency.resultCode = String(grpcStatusCode);
        }
        var target = getDependencyTarget(span);
        if (target) {
            remoteDependency.target = "".concat(target);
        }
        else if (rpcSystem) {
            remoteDependency.target = String(rpcSystem);
        }
    }
    return remoteDependency;
}
function createRequestData(span) {
    var requestData = {
        name: span.name,
        success: span.status.code != api_1.SpanStatusCode.ERROR,
        resultCode: "0",
        duration: 0,
        url: "",
        source: undefined
    };
    var httpMethod = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_METHOD];
    var grpcStatusCode = span.attributes[semantic_conventions_1.SemanticAttributes.RPC_GRPC_STATUS_CODE];
    if (httpMethod) {
        // Try to get request name for server spans
        if (span.kind == api_1.SpanKind.SERVER) {
            var httpRoute = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_ROUTE];
            var httpUrl = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_URL];
            if (httpRoute) {
                requestData.name = "".concat(httpMethod, " ").concat(httpRoute);
            }
            else if (httpUrl) {
                try {
                    var url = new url_1.URL(String(httpUrl));
                    requestData.name = "".concat(httpMethod, " ").concat(url.pathname);
                }
                catch (ex) {
                    // Ignore error
                }
            }
        }
        requestData.url = getUrl(span);
        var httpStatusCode = span.attributes[semantic_conventions_1.SemanticAttributes.HTTP_STATUS_CODE];
        if (httpStatusCode) {
            requestData.resultCode = String(httpStatusCode);
        }
    }
    else if (grpcStatusCode) {
        requestData.resultCode = String(grpcStatusCode);
    }
    return requestData;
}
function spanToTelemetryContract(span) {
    var telemetry;
    switch (span.kind) {
        case api_1.SpanKind.CLIENT:
        case api_1.SpanKind.PRODUCER:
        case api_1.SpanKind.INTERNAL:
            telemetry = createDependencyData(span);
            break;
        case api_1.SpanKind.SERVER:
        case api_1.SpanKind.CONSUMER:
            telemetry = createRequestData(span);
            break;
    }
    var spanContext = span.spanContext ? span.spanContext() : span.context(); // context is available in OT API <v0.19.0
    var id = "".concat(spanContext.spanId);
    var duration = Math.round(span.duration[0] * 1e3 + span.duration[1] / 1e6);
    telemetry.id = id;
    telemetry.duration = duration;
    telemetry.properties = createPropertiesFromSpan(span);
    // Azure SDK
    if (span.attributes[Constants.AzNamespace]) {
        if (span.kind === api_1.SpanKind.INTERNAL) {
            telemetry.dependencyTypeName = "".concat(Constants.DependencyTypeName.InProc, " | ").concat(span.attributes[Constants.AzNamespace]);
        }
        if (span.attributes[Constants.AzNamespace] === Constants.MicrosoftEventHub) {
            (0, EventHub_1.parseEventHubSpan)(span, telemetry);
        }
    }
    return telemetry;
}
//# sourceMappingURL=SpanParser.js.map