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

o.a.s.t.ShellBolt log level is always INFO #7954

Closed
mstrucken opened this issue Feb 4, 2025 · 4 comments
Closed

o.a.s.t.ShellBolt log level is always INFO #7954

mstrucken opened this issue Feb 4, 2025 · 4 comments
Assignees
Labels
Milestone

Comments

@mstrucken
Copy link
Contributor

Example bolt written in Python (multilang/resources/log_level.py):

import asyncio
import storm

class LogLevelTestBolt(storm.BasicBolt):
    async def initialize(self, conf, context):
        storm.logInfo("Python bolt starting...")

        storm.logWarn("This is a sample warning")

    async def process(self, tup):
        storm.logError("Error processing tuple with python...")

async def main():
    bolt = LogLevelTestBolt()
    await bolt.run()

asyncio.run(main())

A minimal bolt that extends the ShellBolt used to execute the Python bolt above:

package com.stockpulse.stockstorm.logging;

import org.apache.storm.task.ShellBolt;
import org.apache.storm.topology.IRichBolt;
import org.apache.storm.topology.OutputFieldsDeclarer;

public class PythonLogLevelBolt extends ShellBolt implements IRichBolt {
    public PythonLogLevelBolt() {
        super("python", "log_level.py");
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {

    }

    @Override
    public java.util.Map<String, Object> getComponentConfiguration() {
        return null;
    }
}

Output:

16:30:51.806 [main] WARN  o.a.s.s.o.a.z.s.ServerCnxnFactory - maxCnxns is not configured, using default value 0.
16:30:57.247 [Thread-37-python-logging-executor[2, 2]] INFO  o.a.s.t.ShellBolt - Launched subprocess with pid 17336
16:30:57.248 [Thread-37-python-logging-executor[2, 2]] INFO  o.a.s.t.ShellBolt - Start checking heartbeat...
16:30:57.248 [Thread-39] INFO  o.a.s.t.ShellBolt - ShellLog pid:17336, name:python-logging Python bolt starting...
16:30:57.248 [Thread-39] INFO  o.a.s.t.ShellBolt - ShellLog pid:17336, name:python-logging This is a sample warning
16:30:57.251 [Thread-39] INFO  o.a.s.t.ShellBolt - ShellLog pid:17336, name:python-logging Error processing tuple with python...

Expected output:

16:30:51.806 [main] WARN  o.a.s.s.o.a.z.s.ServerCnxnFactory - maxCnxns is not configured, using default value 0.
16:30:57.247 [Thread-37-python-logging-executor[2, 2]] INFO  o.a.s.t.ShellBolt - Launched subprocess with pid 17336
16:30:57.248 [Thread-37-python-logging-executor[2, 2]] INFO  o.a.s.t.ShellBolt - Start checking heartbeat...
16:30:57.248 [Thread-39] INFO  o.a.s.t.ShellBolt - ShellLog pid:17336, name:python-logging Python bolt starting...
16:30:57.248 [Thread-39] WARN  o.a.s.t.ShellBolt - ShellLog pid:17336, name:python-logging This is a sample warning
16:30:57.251 [Thread-39] ERROR o.a.s.t.ShellBolt - ShellLog pid:17336, name:python-logging Error processing tuple with python...
@mstrucken
Copy link
Contributor Author

mstrucken commented Feb 4, 2025

The essential code from multilang/resources/storm.py:

def sendMsgToParent(msg):
    print(json_encode(msg))
    print("end")
    sys.stdout.flush()

def log(msg, level=2):
    sendMsgToParent({"command": "log", "msg": msg, "level":level})

def logTrace(msg):
    log(msg, 0)

def logDebug(msg):
    log(msg, 1)

def logInfo(msg):
    log(msg, 2)

def logWarn(msg):
    log(msg, 3)

def logError(msg):
    log(msg, 4)

The json encoded messages:

{"command": "log", "msg": "Python bolt starting...", "level": 2}
{"command": "log", "msg": "This is a sample warning", "level": 3}
{"command": "log", "msg": "Error processing tuple with python...", "level": 4}

A single message is deserialized using org.apache.storm.multilang.JsonSerializer:

    public ShellMsg readShellMsg() throws IOException, NoOutputException {
        JSONObject msg = (JSONObject)this.readMessage();
        ShellMsg shellMsg = new ShellMsg();
        String command = (String)msg.get("command");
		
	// ...	
		
        if (command.equals("log")) {
            Object logLevelObj = msg.get("level");
            if (logLevelObj != null && logLevelObj instanceof Long) {
                long logLevel = (Long)logLevelObj;
                shellMsg.setLogLevel((int)logLevel);
            }
        }

        return shellMsg;
    }

But logLevelObj is not an instance of Long but an instance of Integer.

@rzo1
Copy link
Contributor

rzo1 commented Feb 4, 2025

Thanks for the report. Do you want to create a PR for it?

@mstrucken
Copy link
Contributor Author

To be a little more relaxed about the deserialized numeric type, the check could be changed as follows:

if (command.equals("log")) {
	Object logLevelObj = msg.get("level");
	if (logLevelObj != null && logLevelObj instanceof Number) {
		int logLevel = ((Number) logLevelObj).intValue();
		shellMsg.setLogLevel(logLevel);
	}
}

@rzo1 rzo1 added the bug label Feb 4, 2025
@rzo1 rzo1 added this to the 2.8.1 milestone Feb 4, 2025
@mstrucken
Copy link
Contributor Author

Will create a PR for this, @rzo1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants