Skip to content
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

Provide a way to customize default serviceName in RequestLog #3232

Closed
ikhoon opened this issue Dec 17, 2020 · 14 comments
Closed

Provide a way to customize default serviceName in RequestLog #3232

ikhoon opened this issue Dec 17, 2020 · 14 comments
Milestone

Comments

@ikhoon
Copy link
Contributor

ikhoon commented Dec 17, 2020

The default serviceName of a service is an FQCN of the innermost class.
And a serviceName could get overridden by ctx.logBuilder().name(serviceName, methodName).
Sometimes, users want to globally change the serviceName convention to a simple name of the innermost class.

We might provide an option to ServerBuilder such as:

Server.builder()
     .serviceNaming(serviceName -> {
          var lastDotIndex = serviceName.lastIndexOf('.');
          if (lastDotIndex > -1) {
              return serviceName.substring(lastDotIndex, serviceName.length());
          }
          ...
     });

And we can also provide a built-in abbreviation algorithm like logback's Conversion Word.

ServiceNameRule.shorten(15);
@ikhoon ikhoon changed the title Provide a way to customize default serviceName RequestLog Provide a way to customize default serviceName in RequestLog Dec 17, 2020
@hexoul
Copy link
Contributor

hexoul commented Dec 17, 2020

For me, it should be useful for sure. IMHO, not only abbreviation algorithm but also other rules seems good to be flags. For instance,

  1. ServiceNamingRule.dot.last(2) to pick last two concatenation separated by dot.
  2. ServiceNamingRule.simple to pick just class name.
  3. ServiceNamingRule.shorten(15)

@ikhoon
Copy link
Contributor Author

ikhoon commented Dec 17, 2020

That's a nice suggestion. Are you interested in sending a PR? 😉

@hexoul
Copy link
Contributor

hexoul commented Dec 17, 2020

I hope so. 🤣 I am curious about the preference for this of you. If the user invokes ServerBuilder#serviceNaming and injects MeterIdPrefixFunction, should it be combinable? how can we deal with?

https://github.com/line/armeria/blob/master/spring/boot2-autoconfigure/src/main/java/com/linecorp/armeria/spring/AbstractArmeriaAutoConfiguration.java#L74-L76

@ikhoon
Copy link
Contributor Author

ikhoon commented Dec 17, 2020

I think ServerBuilder.serviceNaming could be applied to RequestLog.serviceName if a user does not specify serviceName explicitly.
MeterIdPrefixFunction will use RequestLog.serviceName itself without any modifications.

@ikhoon
Copy link
Contributor Author

ikhoon commented Dec 17, 2020

The ServerBuilder#serviceNaming will customize the populated newServiceName in the following code.

// Set serviceName from ServiceType or innermost class name
if (newServiceName == null) {
if (rpcReq != null) {
final String serviceType = rpcReq.serviceType().getName();
if ("com.linecorp.armeria.internal.common.grpc.GrpcLogUtil".equals(serviceType)) {
// Parse gRPC serviceName and methodName
final String fullMethodName = rpcReq.method();
final int methodIndex = fullMethodName.lastIndexOf('/');
newServiceName = fullMethodName.substring(0, methodIndex);
if (newName == null) {
newName = fullMethodName.substring(methodIndex + 1);
}
} else {
newServiceName = serviceType;
}
} else if (config != null) {
newServiceName = getInnermostServiceName(config.service());
}
}

@hexoul
Copy link
Contributor

hexoul commented Dec 17, 2020

Thanks for the references! Let me take a look more in considering that way.

@hexoul
Copy link
Contributor

hexoul commented Feb 9, 2021

Before PR, I would like to share the plan first. First of all, I consider to support serviceNaming(Function) without ServiceNameRule and improve later.

For me, the config is supposed to be delivered from ServiceConfig and used under DefaultRequestLog you referred.
In other words, I will propose

  • AbstractServiceBindingBuilder#serviceNaming
  • ServiceBindingBuilder#serviceNaming
  • ServiceConfigSetters#serviceNaming
  • DefaultServiceConfigSetters#serviceNaming

and call like serviceName = config.serviceNaming().apply(newServiceName) instead of serviceName = newServiceName in DefaultRequestLog#setNamesIfAbsent.

If you mind something, please give me an opinion.

@ikhoon
Copy link
Contributor Author

ikhoon commented Feb 10, 2021

As you know, users can customize the default serviceName using ServiceBindingBuilder.defaultServiceName().
That means we don't need to serviceNaming rule at a service level.
Is it better to only apply to a server level by adding ServerBuilder.serviceNaming(ServiceNaming serviceNaming)?

and call like serviceName = config.serviceNaming().apply(newServiceName) instead of serviceName = newServiceName in DefaultRequestLog#setNamesIfAbsent.

Then, this should be ctx.config().server().config().serviceNaming().apply(...).

@hexoul
Copy link
Contributor

hexoul commented Feb 10, 2021

users can customize the default serviceName using ServiceBindingBuilder.defaultServiceName().

I also thought the case that a user uses serviceNaming without using defaultServiceName. It was because I consider serviceNaming as a post processor. For example, even if users set a default service name to blahblah and the function which picks first two letters is given, the service name become bl finally. IMHO, it will be more useful with logback's shorten algorithm.

If we only apply the rule in server level not service level as you said, is it better to name ServerBuilder#defaultServiceNaming instead of just serviceNaming?

In short, it depends on needs. WDYT?

@ikhoon
Copy link
Contributor Author

ikhoon commented Feb 10, 2021

For me, it should be useful for sure. IMHO, not only abbreviation algorithm but also other rules seems good to be flags. For instance,

1. `ServiceNamingRule.dot.last(2)` to pick last two concatenation separated by dot.

2. `ServiceNamingRule.simple` to pick just class name.

3. `ServiceNamingRule.shorten(15)`

You don't have to implement all of these implementations at once. You might want to start by designing an API and add more implementations later.

@ikhoon
Copy link
Contributor Author

ikhoon commented Feb 10, 2021

I also thought the case that a user uses serviceNaming without using defaultServiceName. It was because I consider serviceNaming as a post processor. For example, even if users set a default service name to blahblah and the function which picks first two letters is given, the service name become bl finally. IMHO, it will be more useful with logback's shorten algorithm.

A serviceNaming function could be applied to a defaultServiceName.
However, I am wondering if users need a serviceNaming rule for a specific service.
Because if a defaulServiceName is set, users already knows when serviceNaming(...) is configured.

Server.builder()
      .route()
      .defaultServiceName("foobar")
      .serviceNaming(name -> name.substring(...))
      .build(new MyService())

Do you have cases that such sophisticated serviceNaming rules are required? Otherwise, I prefer ServerBuilder.serviceNaming() to give simplicity and reduce confusion. :-)

@hexoul
Copy link
Contributor

hexoul commented Feb 10, 2021

ServerBuilder.serviceNaming()

I see. It seems that I unnecessarily worried layered serviceNaming. Agreed that the suggestion makes the problem simple and reduce confusion. Let me try with that way. Thanks. :)

trustin pushed a commit that referenced this issue Apr 6, 2021
Motivation
- #3232 Provide a way to customize default `serviceName` in RequestLog

Modifications
- Introduce `ServiceNaming` for per-service naming and global naming.
  - For per-service naming, `ServiceBindingBuilder#defaultServiceNaming()` is added.
  - For global naming, `ServerBuilder#defaultServiceNaming()` is added.
  - To prioritize, `VirtualHost` is used.

Result
- `ServerBuilder` provides a way to apply a naming rule to the service names globally.
- `ServiceBindingBuilder` provides a way to apply a naming rule to the service names under bound services.
trustin pushed a commit that referenced this issue Apr 27, 2021
Related #3232 #3366

Motivation:
- Provide a way to shorten a service name in logging.

Modifications:
- Implement `ShortenedServiceNameProvider` by using forked [`TargetLengthBasedClassNameAbbreviator`](https://github.com/qos-ch/logback/blob/master/logback-classic/src/main/java/ch/qos/logback/classic/pattern/TargetLengthBasedClassNameAbbreviator.java).
- Apply caching to abbreviate. ref. [`CachingAbbreviator`](https://github.com/logstash/logstash-logback-encoder/blob/master/src/main/java/net/logstash/logback/CachingAbbreviator.java).
- Introduce `TemporaryThreadLocals.intArray(int)` to reuse the int array in the future.

Result:
- One more option for `ServiceNaming`, `ServiceNaming.shorten(int)`, to shorten a service name.
- `ServiceNaming.shorten()` as a shortcut of `ServiceNaming.shorten(0)`.
@hexoul
Copy link
Contributor

hexoul commented May 6, 2021

Can we close this issue? @ikhoon

@ikhoon ikhoon added this to the 1.7.0 milestone May 6, 2021
@ikhoon
Copy link
Contributor Author

ikhoon commented May 6, 2021

Nice catch! This was fixed by #3453.

@ikhoon ikhoon closed this as completed May 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants