Azure Functions HTTPTrigger Node.js: bind/call context.log() in my class

79 Views Asked by At

I want to use Azure Functions' context logging methods in my own class depending on the first word: if str starts with error then use context.error(str), otherwise use context.log(str).

I think I have to bind the function but cannot make it work. Full code here: https://runjs.co/s/vyCXfFJ$8

I was thinking of a one-liner but the following gives me the error message Exception: Cannot read private member from an object whose class did not declare it:

class Foo {
    context;
    constructor(context) {
        this.context = context;
    }
    log(...args) {
        return (args.length > 0 && typeof args[0] == "string" && args[0].toLowerCase().startsWith('error') ? this.context.error : this.context.log)(...args);
    }
}

It works using if-else so I have a workaround but I wanted to understand the underlying problem. Who understands and can help?

if (args.length > 0 && typeof args[0] == "string" && args[0].toLowerCase().startsWith('error')) {
    this.context.error(...args);
} else {
    this.context.log(...args);
}

I tried to use .bind() but I'm getting the same error:

return (args.length > 0 && typeof args[0] == "string" && args[0].toLowerCase().startsWith('error') ? this.context.error : this.context.log).bind(this.context)(...args);
1

There are 1 best solutions below

1
Pravallika KV On BEST ANSWER

I tried using your code in my environment and got expected results:

  • Here I tried using both if-else condition and the return statements to check if I'm getting the same results.
const { app } = require('@azure/functions');

const contextPathPrefix = 'context';

app.http(contextPathPrefix, {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    route: `${contextPathPrefix}/{**path}`,
    handler: async (request, context) => {
        const body = 'test';
        const foo = new Foo(context);
        foo.log(body);
        const bar = new Bar(context);
        bar.log(body);
        const baz = new Baz({context,spam:'eggs'});
        baz.log(body);
        baz.log('Error: Lorem ipsum dolor sit amet.');
        return { body };
    }
});

class Foo {
    context;
    constructor(context) {
        this.context = context;
    }
    log(...args) {
        if(args.length > 0 && typeof args[0] == "string" && args[0].toLowerCase().startsWith('error')) {
            this.context.error(...args);
        } else {
            this.context.log(...args);
        }
        return (args.length > 0 && typeof args[0] == "string" && args[0].toLowerCase().startsWith('error') ? this.context.error : this.context.log).bind(this.context)(...args);
    }
}

class Bar extends Foo {
    constructor(...args) {
        super(...args);
    }
}

class Baz extends Bar {
    constructor({context = null, ...others} = {}) {
        super(context);
        this.log('others:', others);
    }
}

Console Output if the context starts with Error:

For detailed output, run func with --verbose flag.
[2023-11-29T07:09:15.700Z] Host lock lease acquired by instance ID '000000000000000000000000F72731CC'.
[2023-11-29T07:09:24.858Z] Executing 'Functions.context' (Reason='This function was programmatically called via the host APIs.', Id=ac28b57f-0b38-42a1-9df9-3869f23de91a)
[2023-11-29T07:09:24.951Z] test
[2023-11-29T07:09:24.951Z] others: { spam: 'eggs' }
[2023-11-29T07:09:24.951Z] test
[2023-11-29T07:09:24.951Z] test
[2023-11-29T07:09:24.956Z] test
[2023-11-29T07:09:24.957Z] test

[2023-11-29T07:09:24.958Z] Error: Lorem ipsum dolor sit amet.
[2023-11-29T07:09:24.959Z] Error: Lorem ipsum dolor sit amet.

[2023-11-29T07:09:24.951Z] others: { spam: 'eggs' }
[2023-11-29T07:09:24.951Z] test
[2023-11-29T07:09:25.090Z] Executed 'Functions.context' (Succeeded, Id=ac28b57f-0b38-42a1-9df9-3869f23de91a, Duration=255ms)

enter image description here

Console Output if the context starts anything else other than Error:

Case 1:

Code Snippet:

baz.log(body);
baz.log('log: Lorem ipsum dolor sit amet.');

Output:

For detailed output, run func with --verbose flag.
[2023-11-29T07:09:15.700Z] Host lock lease acquired by instance ID '000000000000000000000000F72731CC'.
[2023-11-29T07:09:24.858Z] Executing 'Functions.context' (Reason='This function was programmatically called via the host APIs.', Id=ac28b57f-0b38-42a1-9df9-3869f23de91a)
[2023-11-29T07:09:24.951Z] test
[2023-11-29T07:09:24.951Z] others: { spam: 'eggs' }
[2023-11-29T07:09:24.951Z] test
[2023-11-29T07:09:24.951Z] test
[2023-11-29T07:09:24.956Z] test
[2023-11-29T07:09:24.957Z] test

[2023-11-29T07:09:24.958Z] log: Lorem ipsum dolor sit amet.
[2023-11-29T07:09:24.959Z] log: Lorem ipsum dolor sit amet.

[2023-11-29T07:09:24.951Z] others: { spam: 'eggs' }
[2023-11-29T07:09:24.951Z] test
[2023-11-29T07:09:25.090Z] Executed 'Functions.context' (Succeeded, Id=ac28b57f-0b38-42a1-9df9-3869f23de91a, Duration=255ms)

enter image description here

Case 2:

Code Snippet:

baz.log(body);
baz.log('text: Lorem ipsum dolor sit amet.');

Output:

For detailed output, run func with --verbose flag.
[2023-11-29T07:19:34.291Z] Host lock lease acquired by instance ID '000000000000000000000000F72731CC'.
[2023-11-29T07:19:38.841Z] Executing 'Functions.context' (Reason='This function was programmatically called via the host APIs.', Id=86a82de0-0c0a-4437-826a-008447283f7e)
[2023-11-29T07:19:38.942Z] test
[2023-11-29T07:19:38.942Z] others: { spam: 'eggs' }
[2023-11-29T07:19:38.942Z] test
[2023-11-29T07:19:38.942Z] others: { spam: 'eggs' }
[2023-11-29T07:19:38.942Z] test
[2023-11-29T07:19:38.948Z] test

[2023-11-29T07:19:38.949Z] text: Lorem ipsum dolor sit amet.
[2023-11-29T07:19:38.950Z] text: Lorem ipsum dolor sit amet.

[2023-11-29T07:19:38.942Z] test
[2023-11-29T07:19:38.946Z] test
[2023-11-29T07:19:39.095Z] Executed 'Functions.context' (Succeeded, Id=86a82de0-0c0a-4437-826a-008447283f7e, Duration=279ms)

enter image description here