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

Add SLF4J logging support for Appium local service #1014

Conversation

alexander-poulikakos
Copy link
Contributor

Change list

Add possibilty to enable server output data logging through SLF4J loggers. This allow server output data to be configured with your preferred logging frameworks (e.g. java.util.logging, logback, log4j).

Types of changes

  • No changes in production code.
  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Details

Normal use case:

	    AppiumDriverLocalService service = ...
	    service.clearOutPutStreams();
	    service.enableDefaultSlf4jLoggingOfOutputData(); // <-- add this method call
	    service.start();

By default log messages are:

  • logged at INFO level, unless log message is pre-fixed by [debug] then logged at DEBUG level.
  • logged by a SLF4J logger instance with a logger name corresponding to the appium sub module as prefixed in log message (logger name is transformed to lower case, no spaces and prefixed with "appium.service.").

Example of log messages:

  • Log message "[ADB] Cannot read version codes of " is logged by logger: appium.service.adb at level INFO
  • Log message "[debug] [XCUITest] Xcode version set to 'x.y.z' " is logged by logger appium.service.xcuitest at level DEBUG

More general purposes
These methods are provided for more general use cases:

service.addSlf4jLogMessageConsumer(BiConsumer);
service.addLogMessageConsumer(Consumer)

@mykola-mokhnach
Copy link
Contributor

Please adjust indentation in all source files

*/
public void enableDefaultSlf4jLoggingOfOutputData() {
addSlf4jLogMessageConsumer((logMessage, ctx) -> {
if (ctx.level().equals(DEBUG)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mapping is not sufficient, since Appium server uses more levels, for example warn and error

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add the other levels as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I have never seen an actual log message on either warn/error level. Do you know if they follow same format as debug? i.e. log message is prefixed with log level. Info level tag is not added in log message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just able to trigger a WARNmessage, but there is no log level indication in the log message it self. So will ignore warn and error levels for now.

Example

[Appium] Deprecated server args: 
[Appium]   --device-name => --default-capabilities '{"deviceName":"someName"}'

According to this, the above log message is at WARNlevel:
https://github.com/appium/appium/blob/7a00b3f875991ba1d95359ed53a3eda47911f64b/lib/main.js#L44

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the actual level is added there if logging timestamp is enabled:

2018-08-31 08:17:13:813 - info: [debug] [JSONWP Proxy] Got response with status 200: {"value":{"using":"class chain","value":"**/XCUIElementTypeCollectionView[`name == 'add_participants.list'`]/XCUIElementTypeCell[$name == 'user_cell.name' AND value == 'qrj7pcz5'$]","description":"unable to find an element"},"sessionId":"A4FBAD14-ED57-46D4-9407-B91C76BCB415","status":7}
2018-08-31 08:17:13:814 - info: [debug] [MJSONWP] Matched JSONWP error code 7 to NoSuchElementError
2018-08-31 08:17:13:815 - error: [W3C] Encountered internal error running command: NoSuchElementError: An element could not be located on the page using the given search parameters.
2018-08-31 08:17:13:815 - error: [W3C]     at XCUITestDriver.callee$0$0$ (/usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/lib/commands/find.js:130:13)


static Slf4jLogMessageContext parseSlf4jContextFromLogMessage(String logMessage) {
Matcher m = LOGGER_CONTEXT_PATTERN.matcher(logMessage);
String loggerName = "appium.service";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in the constant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following you on this. What should be in the constant? Which constant?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private static final String LOGGER_NAME

* @return {@link Logger} instance associated with this context.
*
*/
public Logger logger() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

java getters usually start with get

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix that

@alexander-poulikakos
Copy link
Contributor Author

thanks for comments! What should I adjust indentation to? it seems to match the rest of the code lines.

@alexander-poulikakos
Copy link
Contributor Author

@mykola-mokhnach Can you please give more context regarding you comment Please adjust indentation in all source files. What should the indentation? I don't see it differ from other code lines.

@mykola-mokhnach
Copy link
Contributor

1
2

@alexander-poulikakos
Copy link
Contributor Author

@mykola-mokhnach How many spaces should it be per indentation?

@mykola-mokhnach
Copy link
Contributor

4 spaces

@appium appium deleted a comment Aug 31, 2018
@appium appium deleted a comment Aug 31, 2018
@appium appium deleted a comment from alexander-poulikakos Aug 31, 2018
@alexander-poulikakos
Copy link
Contributor Author

@mykola-mokhnach
getter names fixed
indentation fixed
constant fixed
javadoc fixed

regarding loglevel error and warn I'm skipping those according to comment above (log level tag is not present in log message -> can't parse it)

Anything else that I have missed?

*/
public void enableDefaultSlf4jLoggingOfOutputData() {
addSlf4jLogMessageConsumer((logMessage, ctx) -> {
if (ctx.getLevel().equals(DEBUG)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is anyway not very accurate, since this [debug] prefix is also not always added to debug logs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mykola-mokhnach So what do you sugests instead? Should all be logged at INFO level? As it is now log messages with [debug] prefix is logged at DEBUG level. That is better than nothing if you ask me.

});
}

static Slf4jLogMessageContext parseSlf4jContextFromLogMessage(String logMessage) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

codacy does not like package-level visibility. Please add public

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mykola-mokhnach There is a big difference between public and package private. Making it public will make it part of the public API, which is not desired in this case.

I don't think we should make an implementation detail public just because codacy says so, or?

*
*/
public void addLogMessageConsumer(Consumer<String> consumer) {
addOutPutStream(new OutputStream() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Output

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following this comment? addOutPutStream(...) is the name of an already existing method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a typo in this word

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mykola-mokhnach
I'm still not following what this has to do with this PR?
As I said the addOutPutStream(...) method is already existing. Changing its name would be a breaking change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then yes, it is better to keep it as is if it was there

assertLoggerContext(DEBUG, "appium.service.xcuitest",
"[debug] [XCUITest] Xcode version set to 'x.y.z' ");
assertLoggerContext(DEBUG, "appium.service.jsonwpproxy",
"[debug] [JSONWP Proxy] Proxying [GET /status] to [GET http://localhost:18218/status] with no body");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would you parse messages with timestamps like 2018-08-31 08:17:13:741 - info: [debug] [JSONWP Proxy] Matched '/element' to command name 'findElement' ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as mentioned in javadoc. this feature is not supported when --log-timestamp is enabled.

from javadoc:
NOTE2: it is required that {@code --log-timestamp} server flag is {@code false}.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List<String> log = new ArrayList<>();
service = buildDefaultService();
service.clearOutPutStreams();
service.addLogMessageConsumer(log::add);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we also have a possibility to remove a consumer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Essentially a consumer in this case is an OutputStream (as added with addOutPutStream(...) method). So consumers can be removed with the clearOutPutStreams() method.

* BiConsumer block to be executed when a log message is
* available.
*/
public void addSlf4jLogMessageConsumer(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it useful to return self instance from such methods, so one can chain them

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree it is nice to return self to chain method calls. But no other methods in this class does that, so I figured to follow same pattern as other methods. Would be strange if only this method returned self.

@alexander-poulikakos
Copy link
Contributor Author

I just realized these methods does not do a null check of given arguments. Will fix that.

addSlf4jLogMessageConsumer(...)
addLogMessageConsumer(...)

@appium appium deleted a comment Aug 31, 2018
@appium appium deleted a comment Sep 3, 2018
@appium appium deleted a comment Sep 3, 2018
@alexander-poulikakos
Copy link
Contributor Author

Will this be merged?

@SrinivasanTarget SrinivasanTarget merged commit a873737 into appium:master Sep 7, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants