-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-7834: Extend collected logs in system test services to include heap dumps #6158
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
Changes from all commits
68af2bc
3286d69
c30cf90
b964036
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -42,6 +42,7 @@ class ConnectServiceBase(KafkaPathResolverMixin, Service): | |
| PID_FILE = os.path.join(PERSISTENT_ROOT, "connect.pid") | ||
| EXTERNAL_CONFIGS_FILE = os.path.join(PERSISTENT_ROOT, "connect-external-configs.properties") | ||
| CONNECT_REST_PORT = 8083 | ||
| HEAP_DUMP_FILE = os.path.join(PERSISTENT_ROOT, "connect_heap_dump.bin") | ||
|
|
||
| # Currently the Connect worker supports waiting on three modes: | ||
| STARTUP_MODE_INSTANT = 'INSTANT' | ||
|
|
@@ -61,6 +62,9 @@ class ConnectServiceBase(KafkaPathResolverMixin, Service): | |
| "connect_stderr": { | ||
| "path": STDERR_FILE, | ||
| "collect_default": True}, | ||
| "connect_heap_dump_file": { | ||
| "path": HEAP_DUMP_FILE, | ||
| "collect_default": True} | ||
| } | ||
|
|
||
| def __init__(self, context, num_nodes, kafka, files, startup_timeout_sec = 60): | ||
|
|
@@ -160,8 +164,8 @@ def restart_node(self, node, clean_shutdown=True): | |
| def clean_node(self, node): | ||
| node.account.kill_process("connect", clean_shutdown=False, allow_fail=True) | ||
| self.security_config.clean_node(node) | ||
| all_files = " ".join([self.CONFIG_FILE, self.LOG4J_CONFIG_FILE, self.PID_FILE, self.LOG_FILE, self.STDOUT_FILE, self.STDERR_FILE, self.EXTERNAL_CONFIGS_FILE] + self.config_filenames() + self.files) | ||
| node.account.ssh("rm -rf " + all_files, allow_fail=False) | ||
| other_files = " ".join(self.config_filenames() + self.files) | ||
| node.account.ssh("rm -rf -- %s %s" % (ConnectServiceBase.PERSISTENT_ROOT, other_files), allow_fail=False) | ||
|
|
||
| def config_filenames(self): | ||
| return [os.path.join(self.PERSISTENT_ROOT, "connect-connector-" + str(idx) + ".properties") for idx, template in enumerate(self.connector_config_templates or [])] | ||
|
|
@@ -252,6 +256,14 @@ def _rest_with_retry(self, path, body=None, node=None, method="GET", retries=40, | |
| def _base_url(self, node): | ||
| return 'http://' + node.account.externally_routable_ip + ':' + str(self.CONNECT_REST_PORT) | ||
|
|
||
| def append_to_environment_variable(self, envvar, value): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is the logic for this, including the different ways
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I ended up adding the heap jvm arguments in That's why I'm adding this method - unused here - that can be used by tests that inherit this class. Let me know if you think I should remove.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, in general the construction of commands could be cleaned up quite a bit for extensibility -- i think we tend to forget about the importance/value of doing this when writing tests in the Kafka repo, but these classes should be reusable and extensible. this approach seems pretty error-prone, although at least it should consistently fail if the quoting gets messed up since you'll have invalid extra args on the command line. |
||
| env_opts = self.environment[envvar] | ||
| if env_opts is None: | ||
| env_opts = "\"%s\"" % value | ||
| else: | ||
| env_opts = "\"%s %s\"" % (env_opts.strip('\"'), value) | ||
| self.environment[envvar] = env_opts | ||
|
|
||
|
|
||
| class ConnectStandaloneService(ConnectServiceBase): | ||
| """Runs Kafka Connect in standalone mode.""" | ||
|
|
@@ -266,7 +278,10 @@ def node(self): | |
|
|
||
| def start_cmd(self, node, connector_configs): | ||
| cmd = "( export KAFKA_LOG4J_OPTS=\"-Dlog4j.configuration=file:%s\"; " % self.LOG4J_CONFIG_FILE | ||
| cmd += "export KAFKA_OPTS=%s; " % self.security_config.kafka_opts | ||
| heap_kafka_opts = "-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%s" % \ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we seem to duplicate this pattern of setting constants, is there any opportunity to relocate and reduce to one copy of these constants (given they should be same across all our java services)?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With each service setting its security configs in |
||
| self.logs["connect_heap_dump_file"]["path"] | ||
| other_kafka_opts = self.security_config.kafka_opts.strip('\"') | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what's happening with the various
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I mention above, we often wrap the value of an env var in escaped double quotes. To append contents, we first need to remove those. If they don't exist, strip is a no-op. |
||
| cmd += "export KAFKA_OPTS=\"%s %s\"; " % (heap_kafka_opts, other_kafka_opts) | ||
| for envvar in self.environment: | ||
| cmd += "export %s=%s; " % (envvar, str(self.environment[envvar])) | ||
| cmd += "%s %s " % (self.path.script("connect-standalone.sh", node), self.CONFIG_FILE) | ||
|
|
@@ -314,7 +329,10 @@ def __init__(self, context, num_nodes, kafka, files, offsets_topic="connect-offs | |
| # connector_configs argument is intentionally ignored in distributed service. | ||
| def start_cmd(self, node, connector_configs): | ||
| cmd = "( export KAFKA_LOG4J_OPTS=\"-Dlog4j.configuration=file:%s\"; " % self.LOG4J_CONFIG_FILE | ||
| cmd += "export KAFKA_OPTS=%s; " % self.security_config.kafka_opts | ||
| heap_kafka_opts = "-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%s" % \ | ||
| self.logs["connect_heap_dump_file"]["path"] | ||
| other_kafka_opts = self.security_config.kafka_opts.strip('\"') | ||
| cmd += "export KAFKA_OPTS=\"%s %s\"; " % (heap_kafka_opts, other_kafka_opts) | ||
| for envvar in self.environment: | ||
| cmd += "export %s=%s; " % (envvar, str(self.environment[envvar])) | ||
| cmd += "%s %s " % (self.path.script("connect-distributed.sh", node), self.CONFIG_FILE) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these all under
PERSISTENT_ROOT? if yes, can we just handlePERSISTENT_ROOTand not worry about individual files?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the
other_filesare not necessarily underPERSISTENT_ROOTWhat is under it for sure is:
self.CONFIG_FILE, self.LOG4J_CONFIG_FILE, self.PID_FILE, self.LOG_FILE, self.STDOUT_FILE, self.STDERR_FILE, self.EXTERNAL_CONFIGS_FILEwhich I removed from explicit listing and I'm removing withPERSISTENT_ROOTaltogether.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I get that though I think that's just tech debt. for any test related files, we really shouldn't be using anything other than
PERSISTENT_ROOTso that we can at least attempt to ensure each test/service gets a clean workspace