I'm trying to setup logging across my typescript program, using log4javascript
.
However I have no idea how to retrieve the function names using reflection (rather than typed manually).
Ideally I want to emulate what I do in C#
:
public class Foo
{
private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(typeof(Foo));
public Foo()
{
}
public FooMethod()
{
try {
logger.Logger.Log(this.GetType(), log4net.Core.Level.Trace, "Entering" + MethodBase.GetCurrentMethod().Name, null);
// code
}
catch (e) {
logger.Logger.Log(this.GetType(), log4net.Core.Level.Debug, ex.Message, null);
}
finally {
logger.Logger.Log(this.GetType(), log4net.Core.Level.Trace, "Exiting" + MethodBase.GetCurrentMethod().Name, null);
}
}
}
How can I do this in Typescript
? All I can do is get the class name.
class Foo {
private static logger: log4javascript.Logger = log4javascript.getLogger(getName(Foo));
constructor() {
}
FooFunction() {
try {
SymDataSource.logger.trace("Entering: " + getName(Foo.prototype.FooFunction));
// code
} catch (e) {
SymDataSource.logger.debug("Exception: " + getName(Foo.prototype.FooFunction), e);
} finally {
SymDataSource.logger.trace("Exiting: " + getName(Foo.prototype.FooFunction));
}
}
}
function getName(obj: any): string {
if (obj.name) {
return obj.name;
}
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec((<any> obj).constructor.toString());
return (results && results.length > 1) ? results[1] : "";
}
The class name returns correctly, but the functions return as "Function".
For member functions it is actually not possible to use the simple toString
parsing approach because of the way prototype functions are created e.g. :
Foo.prototype.FooFunction = function () {
return getName(this.FooFunction);
};
Here toString
would give you :
function () {
return getName(this.FooFunction);
};
And you can see that the function name is not present between function () {
.
What you can do is create an inline function (using the awesome fat arrow e.g. return getName(()=>this.FooFunction);
) and parse this local function body to find the function name. Notice that in this way it is still TypeSafe and if you do a rename refactoring there are no magic strings that will go out of sync. So the complete implementation becomes :
class Foo {
static className = getName(Foo);
constructor() {
}
FooFunction() {
return getName(()=>this.FooFunction);
}
}
function getName(obj: any): string {
if (obj.name) {
return obj.name;
}
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec(obj.toString());
var result = results && results.length > 1 && results[1];
// Check to see custom implementation
if(!result){
funcNameRegex = /return _this.(.*);/;
results = (funcNameRegex).exec(obj.toString());
result = results && results.length > 1 && results[1];
}
return result || "";
}
console.log(Foo.className);
var foo = new Foo();
console.log(foo.FooFunction());
which will output :
Foo
FooFunction
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With