I'm trying to setup logging across my typescript program, using log4javascript
.
我正在尝试使用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#
:
理想情况下,我想模仿我在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".
类名返回正确,但函数返回“Function”。
2 个解决方案
#1
4
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. :
对于成员函数,由于创建原型函数的方式,实际上不可能使用简单的toString解析方法。 :
Foo.prototype.FooFunction = function () {
return getName(this.FooFunction);
};
Here toString
would give you :
这里toString会给你:
function () {
return getName(this.FooFunction);
};
And you can see that the function name is not present between function () {
.
你可以看到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 :
你可以做的是创建一个内联函数(使用令人敬畏的胖箭头,例如return getName(()=> this.FooFunction);)并解析这个本地函数体以找到函数名。请注意,通过这种方式,它仍然是TypeSafe,如果进行重命名重构,则没有魔法字符串会不同步。所以完整的实现变成:
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
#2
1
I've ended up making two functions. 1 for current top method in stack, other for the type name.
我最终做了两个功能。 1表示堆栈中当前的top方法,其他表示类型名称。
export function getName(): string {
var result: string = "";
var error: any = new Error("getStack");
var stack: string[] = error.stack
.replace(/^[^\(]+?[\n$]/gm, '') // Remove first useless line
.replace(/^\s+at\s+/gm, '') // Remove 'at'
.replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') // Replace Object.<anon> with {anon}
.replace(/\s\(.*:[0-9]+:[0-9]+\)/gm, '') // Remove filename, col and row
.split('\n');
return stack[1]; // Previous method
}
export function getType(obj: any): string {
if (obj.name) {
return obj.name;
}
var results = /function (.{1,})\(/.exec(obj.constructor.toString());
return (results && results.length > 1) ? results[1] : "";
}
#1
4
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. :
对于成员函数,由于创建原型函数的方式,实际上不可能使用简单的toString解析方法。 :
Foo.prototype.FooFunction = function () {
return getName(this.FooFunction);
};
Here toString
would give you :
这里toString会给你:
function () {
return getName(this.FooFunction);
};
And you can see that the function name is not present between function () {
.
你可以看到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 :
你可以做的是创建一个内联函数(使用令人敬畏的胖箭头,例如return getName(()=> this.FooFunction);)并解析这个本地函数体以找到函数名。请注意,通过这种方式,它仍然是TypeSafe,如果进行重命名重构,则没有魔法字符串会不同步。所以完整的实现变成:
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
#2
1
I've ended up making two functions. 1 for current top method in stack, other for the type name.
我最终做了两个功能。 1表示堆栈中当前的top方法,其他表示类型名称。
export function getName(): string {
var result: string = "";
var error: any = new Error("getStack");
var stack: string[] = error.stack
.replace(/^[^\(]+?[\n$]/gm, '') // Remove first useless line
.replace(/^\s+at\s+/gm, '') // Remove 'at'
.replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') // Replace Object.<anon> with {anon}
.replace(/\s\(.*:[0-9]+:[0-9]+\)/gm, '') // Remove filename, col and row
.split('\n');
return stack[1]; // Previous method
}
export function getType(obj: any): string {
if (obj.name) {
return obj.name;
}
var results = /function (.{1,})\(/.exec(obj.constructor.toString());
return (results && results.length > 1) ? results[1] : "";
}