-
Notifications
You must be signed in to change notification settings - Fork 725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add name and tags to ResolutionContext #1746
Comments
Hey @BurningEnlightenment, thank you for submitting the feature request. At first glance, Implementation proposalSince categories are a well known set of constants, consider the following approach: container.bind(Logger)
.toResolvedValue(
(rootLogger: RootLogger) => rootLogger.child({ category: 'my.category' }),
[RootLogger],
)
.whenTagged(LogCategoryKey, 'my.category'); This binding is able to cover your use case for that specific category. Extracting a function: function bindCategoryLogger(container: Container, category: string): void {
container.bind(Logger)
.toResolvedValue(
(rootLogger: RootLogger) => rootLogger.child({ category }),
[RootLogger],
)
.whenTagged(LogCategoryKey, category);
} Once we got the function, we can add bindings for each category: for (const category of MY_WELL_KNOWN_CATEGORIES) {
bindCategoryLogger(container, category);
} What about the feature request?We should ask if the public API should expose planning related data such as binding constraints. I honestly prefer not do so. Constrained bindings should be the way to determine which service shall be provided as I previously proposed with At the end, the dynamic value you want to implement decides which logger should be relied on given a set of binding constraints, this responsibility belongs to the planner instead. As long as the binding API is powerfull enough to satisfy these kind of use cases, that should be the way to go. I'm keeping the issue open for the sake of discussion, I'd love to hear anyone's thoughts about this. |
The log categories are usually specific to a service and I did consider your approach. Though I hoped I could avoid the tedium of specifying the category twice without implementing some global category registry like the following myself. const MY_WELL_KNOWN_CATEGORIES = new Set<string>();
export function logger(category: string): ParameterDecorator {
MY_WELL_KNOWN_CATEGORIES.add(category);
const tagCategory = tagged(LogCategoryKey, category);
const injectLogger = inject(Logger);
return function (target, propertyKey, parameterIndex) {
tagCategory(target, propertyKey, parameterIndex);
injectLogger(target, propertyKey, parameterIndex);
};
} It is trivial to do, but it feels weird that the planning complexity for a logger has to scale linearly with the number of log categories by design. I took a cursory glance at the binding constraint implementation, it doesn't seem to (be able to) cache plans based on constraints, i.e. assuming all categories are unique we've increased runtime complexity for logger construction from So it is probably more efficient to dynamically generate injection symbols for each log category… const MY_WELL_KNOWN_CATEGORIES = new Map<string, symbol>();
export function logger(category: string): ParameterDecorator {
let loggerServiceId = MY_WELL_KNOWN_CATEGORIES.get(category)
if (loggerServiceId == null) {
loggerServiceId = Symbol(`logger#${category}`);
MY_WELL_KNOWN_CATEGORIES.set(category, loggerServiceId);
}
return inject(loggerServiceId)
} function bindCategoryLogger(container: Container, category: string, loggerId: symbol): void {
container.bind(loggerId)
.toResolvedValue(
(rootLogger: RootLogger) => rootLogger.child({ category }),
[RootLogger],
);
}
for (const [category, loggerId] of MY_WELL_KNOWN_CATEGORIES) {
bindCategoryLogger(container, category, loggerId);
} I opened this issue, because this feels like I'm hacking around an API deficiency, but if it is the intended way to use inversify, so be it. Obviously any problem can be solved with an additional layer of indirection, so another alternative would be to just inject a factory function which wraps |
Well, we should clarify what is
I don't see it that way, but I'm interested to know more about it. What feels hacky? Don't worry about being direct, I strongly believe in constructive criticism as a way of improving 😄. |
First off: I'm sometimes a bit… obsessed with removing overhead and communicate it bit too strongly. I really just wanted to express that this realization made me feel weird. I didn't want to suggest it dominating the overall DI runtime or even causing noticable delays. With that out of the way I was talking about the worst case of only injecting loggers with unique categories with |
It feels like I'm implementing some sort of reflection capability with a global registry. I fully agree that |
Is there an existing proposal similar to this?
What are you proposing?
Expose
name
andtags
on theResolutionContext
interface like they are exposed onBindingConstraints
.Is there any specific group of users that will benefit from this?
Currently we have a custom decorator which combines
@inject()
and@tagged()
to annotate a specific service with metadata which will be used during the resolution / construction of the service.What problems are you trying to solve?
We want to inject logger instances with categories assigned into our services like so
@logger('log.category')
.With inversify v6 we were able to extract the tag from within
toDynamicValue()
and pass it to the logger.Do you have any references or examples that can illustrate your idea?
ah sketch of the current v6 code:
What type of idea is this?
Copy of existing idea: Similar idea exists and this is a copy
The text was updated successfully, but these errors were encountered: