APIs

Show:
"use strict";


const assert = require("node-opcua-assert").assert;

const ServerEngine = require("node-opcua-server").ServerEngine;
const Variant = require("node-opcua-variant").Variant;
const DataType = require("node-opcua-variant").DataType;
const ObjectIds = require("node-opcua-constants").ObjectIds;
const StatusCodes = require("node-opcua-status-code").StatusCodes;
const humanize = require("humanize");

/**
 * @method addVariableWithHumanizeText
 * @param engine
 * @param options
 * @param options.browseName
 * @private
 */
function addVariableWithHumanizeText(namespace, options) {

    assert(options.componentOf || options.organizedBy);
    assert(typeof options.description === "string");

    const variable = namespace.addVariable(options);
    // add the xxxAsText property
    namespace.addVariable({

        propertyOf: variable,

        browseName: options.browseName.name.toString() + "AsText",
        description: options.description + " as text",
        dataType: "String",
        minimumSamplingInterval: options.minimumSamplingInterval,
        value: {
            get: function () {
                const v = options.value.get();
                if (v instanceof Variant) {
                    return new Variant({dataType: DataType.String, value: humanize.filesize(v.value)});
                } else {
                    return v;
                }
            }
        }
    });
}

/**
 *
 * optionally install a CPU Usage and Memory Usage node
 * ( condition : running on linux and require("usage")
 * @method install_optional_cpu_and_memory_usage_node
 * @param server {OPCUAServer}
 *
 */
function install_optional_cpu_and_memory_usage_node(server) {

    const engine = server.engine;
    assert(engine instanceof ServerEngine);

    let usage;
    try {
        usage = require("usage");
    } catch (err) {
        console.log("err", err.message);
        usage = null;
        //xx return;
    }

    const addressSpace = engine.addressSpace;

    const namespace = addressSpace.getOwnNamespace();

    const folder = addressSpace.findNode(ObjectIds.Server_VendorServerInfo);

    let usage_result = {memory: 0, cpu: 100};

    const pid = process.pid;
    const os = require("os");

    if (usage) {

        const options = {keepHistory: true};
        setInterval(function () {
            usage.lookup(pid, options, function (err, result) {
                usage_result = result;
                console.log("result Used Memory: ", humanize.filesize(result.memory), " CPU ", Math.round(result.cpu), " %");
                if (err) { console.log("err ",err); }
            });
        }, 1000);

        namespace.addVariable({

            organizedBy: folder,

            browseName:    "CPUUsage",
            description:   "Current CPU usage of the server process",
            nodeId:        "s=CPUUsage",
            dataType:      "Double",
            minimumSamplingInterval: 1000,
            value: {
                get: function () {
                    if (!usage_result) {
                        return StatusCodes.BadResourceUnavailable;
                    }
                    return new Variant({dataType: DataType.Double, value: Math.round(usage_result.cpu, 2)});
                }
            }
        });


        addVariableWithHumanizeText(namespace,{
            organizedBy: folder,
            browseName:  "MemoryUsage",
            nodeId:      "s=MemoryUsage",
            description: "Current memory usage of the server process",
            dataType:    "Number",
            minimumSamplingInterval: 1000,
            value: {
                get: function () {
                    if (!usage_result) {
                        return StatusCodes.BadResourceUnavailable;
                    }
                    return new Variant({dataType: DataType.UInt32, value: usage_result.memory});
                }
            }
        });

    } else {
        console.log("skipping installation of cpu_usage and memory_usage nodes");
    }

    namespace.addVariable({
        organizedBy: folder,

        browseName: "PercentageMemoryUsed",
        description: "% of  memory used by the server",
        nodeId: "s=PercentageMemoryUsed",
        dataType: "Number",
        minimumSamplingInterval: 1000,
        value: {
            get: function () {
                const percent_used = Math.round((os.totalmem() - os.freemem()) / os.totalmem() * 100);
                return new Variant({dataType: DataType.Double, value: percent_used});
            }
        }
    });

    addVariableWithHumanizeText(namespace, {
        organizedBy: folder,
        browseName: "SystemMemoryTotal",
        description: "Total Memory usage of the server",
        nodeId: "s=SystemMemoryTotal",
        dataType: "Number",
        accessLevel: "CurrentRead",
        minimumSamplingInterval: 1000,
        value: {
            get: function () {
                const memory = os.totalmem();
                return new Variant({dataType: DataType.UInt64, value: memory});
            }
        }
    });

    addVariableWithHumanizeText(namespace,{
        organizedBy: folder,
        browseName: "SystemMemoryFree",
        description: "Free Memory usage of the server in MB",
        nodeId: "s=SystemMemoryFree",
        dataType: "Number",
        accessLevel: "CurrentRead",
        minimumSamplingInterval: 1000,
        value: {
            get: function () {
                const memory = os.freemem();
                return new Variant({dataType: DataType.UInt64, value: memory});
            }
        }
    });

    namespace.addVariable({
        organizedBy: folder,
        browseName: "NumberOfCPUs",
        description: "Number of cpus on the server",
        nodeId: "s=NumberOfCPUs",
        dataType: "Number",
        accessLevel: "CurrentRead",
        minimumSamplingInterval: 1000,
        value: {
            get: function () {
                return new Variant({dataType: DataType.UInt32, value: os.cpus().length});
            }
        }
    });

    namespace.addVariable({
        organizedBy: folder,
        browseName: "Arch",
        description: "ServerArchitecture",
        nodeId: "s=ServerArchitecture",
        dataType: "String",
        accessLevel: "CurrentRead",
        minimumSamplingInterval: 1000,
        value: {
            get: function () {
                return new Variant({dataType: DataType.String, value: os.type()});
            }
        }
    });

    addVariableWithHumanizeText(namespace,{
        organizedBy: folder,
        browseName: "BytesWritten",
        description: "number of bytes written by the server",
        nodeId: "s=BytesWritten",
        dataType: "Number",
        accessLevel: "CurrentRead",
        minimumSamplingInterval: 1000,
        value: {
            get: function () {
                return new Variant({dataType: DataType.UInt64, value: server.bytesWritten});
            }
        }
    });

    addVariableWithHumanizeText(namespace,  {
        organizedBy: folder,
        browseName: "BytesRead",
        description: "number of bytes read by the server",
        nodeId: "s=BytesRead",
        dataType: "Number",
        accessLevel: "CurrentRead",
        minimumSamplingInterval: 1000,
        value: {
            get: function () {
                return new Variant({dataType: DataType.UInt64, value: server.bytesRead});
            }
        }
    });

    namespace.addVariable({
        organizedBy: folder,
        browseName: "TransactionsCount",
        description: "total number of transactions performed the server",
        nodeId: "s=TransactionsCount",
        dataType: "Number",
        accessLevel: "CurrentRead",
        minimumSamplingInterval: 1000,
        value: {
            get: function () {
                return new Variant({dataType: DataType.UInt32, value: server.transactionsCount});
            }
        }
    });

    namespace.addVariable({
        organizedBy: folder,
        browseName: "ConnectionsCount",
        description: "number of active Connections",
        nodeId: "s=ConnectionCount",
        dataType: "String",
        accessLevel: "CurrentRead",
        minimumSamplingInterval: 1000,
        value: {
            get: function () {
                return new Variant({dataType: DataType.String, value: humanize.filesize(server.currentChannelCount)             });
            }
        }
    });

}

exports.install_optional_cpu_and_memory_usage_node = install_optional_cpu_and_memory_usage_node;