# Getting threads from the Gateway

**URL:** <https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447>\
**Category:** Ignition\
**Tags:** ignition81\
**Created:** [April 25, 2024, 1:08pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447 "2024-04-25T13:08:21Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![hw79](https://avatars.discourse-cdn.com/v4/letter/h/838e76/32.png) [@hw79](https://forum.inductiveautomation.com/u/hw79)\
**Post date:** [April 25, 2024, 1:08pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/1 "2024-04-25T13:08:21Z")

</div>

Like the diagnostic dashboard, I made a project with a dashboard to show the threads on the gateway. I'm using `system.util.threadDump()` then parsing that json to get how many of each type of thread and the status.

However, I feel like there may be a better method that's not so resource intensive.

Thoughts?

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [April 25, 2024, 1:25pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/2 "2024-04-25T13:25:01Z")

</div>

You can go [straight to the Java API](https://docs.oracle.com/en/java/javase/17/docs/api/java.management/java/lang/management/ThreadMXBean.html#dumpAllThreads(boolean,boolean)), but then you don't get something in JSON that you can easily pull data out of.

Generating a thread dump is an inherently expensive operation.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [April 25, 2024, 1:36pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/3 "2024-04-25T13:36:15Z")

</div>

> [@Kevin.Herron](#):
>
> inherently expensive operation.

💯

You really shouldn't even leave the gateway's thread monitoring page open.

---

<div class="post-metadata">

**Author:** ![hw79](https://avatars.discourse-cdn.com/v4/letter/h/838e76/32.png) [@hw79](https://forum.inductiveautomation.com/u/hw79)\
**Post date:** [April 25, 2024, 1:39pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/4 "2024-04-25T13:39:11Z")

</div>

Thanks for the info. As having never worked with APIs before, sounds like it's time to learn.

In case anyone was curious, this is what I was running on the gateway every 10 seconds, I had it running every second, but that was... problematic. (putting it lightly)

```python
import json
threadDumpStr = system.util.threadDump()
threadDump = json.loads(threadDumpStr)
webserverTag = '[default]Dashboard/Threads/WebserverThreadCount'
timed_waitingTag = '[default]Dashboard/Threads/TIMED_WAITING'

# Count webserver threads
webserverCount = sum(1 for thread in threadDump['threads'] if thread['name'].startswith('webserver'))

# Count threads with TIMED_WAITING status
timedWaitingCount = sum(1 for thread in threadDump['threads'] if thread['state'] == 'TIMED_WAITING' and thread['name'].startswith('webserver'))

# Write the dataset to a tag
system.tag.write(webserverTag, webserverCount)
system.tag.write(timed_waitingTag, timedWaitingCount)

```

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [April 25, 2024, 1:44pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/5 "2024-04-25T13:44:22Z")

</div>

> [@pturmel](#):
>
> You really shouldn't even leave the gateway's thread monitoring page open.

We cache the results from that route for 5 seconds, but still yes, especially on large systems.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [April 25, 2024, 1:51pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/6 "2024-04-25T13:51:54Z")

</div>

If you're not paying any attention to the stack trace, you can avoid fetching it ([ThreadMXBean (Java SE 17 & JDK 17)](https://docs.oracle.com/en/java/javase/17/docs/api/java.management/java/lang/management/ThreadMXBean.html#getThreadInfo(long%5B%5D,int))) which will make the calls _significantly_ cheaper.

---

<div class="post-metadata">

**Author:** ![hw79](https://avatars.discourse-cdn.com/v4/letter/h/838e76/32.png) [@hw79](https://forum.inductiveautomation.com/u/hw79)\
**Post date:** [April 26, 2024, 3:17pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/7 "2024-04-26T15:17:00Z")

</div>

Is that something I can do through a project? How would that call be structured?

`foo.bar.getAllThreadIDs()`

then

`foo.bar.getThreadInfo(threadArray, 0)`

But I don't know what those somethings are.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [April 26, 2024, 5:18pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/8 "2024-04-26T17:18:08Z")

</div>

Use the static method [here](https://docs.oracle.com/en/java/javase/17/docs/api/java.management/java/lang/management/ManagementFactory.html#getThreadMXBean()) to get an instance of the class, then get your array of thread IDs, then pass that to the call to get thread info.

---

<div class="post-metadata">

**Author:** ![hw79](https://avatars.discourse-cdn.com/v4/letter/h/838e76/32.png) [@hw79](https://forum.inductiveautomation.com/u/hw79)\
**Post date:** [April 29, 2024, 4:34pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/9 "2024-04-29T16:34:06Z")

</div>

I tried that and it doesn't seem like I'm getting the full thread dump from the gateway.

```python
from java.lang.management import ManagementFactory
from java.lang import Thread

# Get the ThreadMXBean instance
thread_mx_bean = ManagementFactory.getThreadMXBean()

# Get a dump of all threads
thread_info_array = thread_mx_bean.dumpAllThreads(True, True)

# Initialize counters
webserver_count = 0
timed_waiting_count = 0

# Process the thread_info_array
for thread_info in thread_info_array:
    # Check if the thread name starts with "Webserver"
    if thread_info.getThreadName().startswith("Webserver"):
        webserver_count += 1
        # Check if the thread state is TIMED_WAITING
    	if thread_info.getThreadState() == Thread.State.TIMED_WAITING:
            timed_waiting_count += 1

# Write the counts to the specified tags
system.tag.write('[default]Dashboard/Threads/WebserverThreadCount', webserver_count)
system.tag.write('[default]Dashboard/Threads/TIMED_WAITING', timed_waiting_count)

```

If I change the .startswith() to something like "Swing" or "Fork" I get some results. With "Webserver" I would expect a "webserver" thread count of around 80 because that's what I can see on the VM when I do a thread dump there.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [April 29, 2024, 5:03pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/10 "2024-04-29T17:03:50Z")

</div>

> [@hw79](#):
>
> If I change the .startswith() to something like "Swing" or "Fork" I get some results. With "Webserver" I would expect a "webserver" thread count of around 80 because that's what I can see on the VM when I do a thread dump there.

That implies you're calling this from a client or designer scope, not the actual gateway. You need to call the script on the gateway to get gateway scoped results.

---

<div class="post-metadata">

**Author:** ![hw79](https://avatars.discourse-cdn.com/v4/letter/h/838e76/32.png) [@hw79](https://forum.inductiveautomation.com/u/hw79)\
**Post date:** [April 29, 2024, 5:26pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/11 "2024-04-29T17:26:13Z")

</div>

I've got it running as a gateway event under scripting, shouldn't that be the correct scope? Or is there something I'm missing with how I'm calling the function?

I understand that if I run it in the script console that it would be the designer scope, but the saved script in the gateway events should run from the gateway?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [April 29, 2024, 5:30pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/12 "2024-04-29T17:30:28Z")

</div>

If it's running as a gateway event, then yes, it should be executing on the gateway, but you also definitely shouldn't see any `Swing` related threads on the gateway.

Do you have Perspective? Can you run it from a button in Perspective to be sure?  
Maybe also print out `thread_info_array`?

---

<div class="post-metadata">

**Author:** ![hw79](https://avatars.discourse-cdn.com/v4/letter/h/838e76/32.png) [@hw79](https://forum.inductiveautomation.com/u/hw79)\
**Post date:** [April 29, 2024, 6:06pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/13 "2024-04-29T18:06:07Z")

</div>

Correct, I only got Swing threads when I ran it from the script console in designer.

Okay, I got it working from the button. I found a few issues. I was calling dumpAllThreads when I should have been calling getThreadInfo

also `.startswith()` is case sensitive.

```python
    from java.lang.management import ManagementFactory
	from java.lang import Thread
	
	# Get the ThreadMXBean instance
	thread_mx_bean = ManagementFactory.getThreadMXBean()
	
	# Get all live thread IDs
	thread_ids = thread_mx_bean.getAllThreadIds()
	
	# Get thread information for the specified threads
	thread_info_array = thread_mx_bean.getThreadInfo(thread_ids)
	
	# thread_info_array to text block
	self.parent.parent.getChild("TextArea").props.text = thread_info_array
	
	# Initialize counters
	webserver_count = 0
	timed_waiting_count = 0
	
	# Process the thread_info_array
	for thread_info in thread_info_array:
		if thread_info is not None:
			# Check if the thread name starts with "Webserver"
			if thread_info.getThreadName().startswith("webserver"):
				webserver_count += 1
			# Check if the thread state is TIMED_WAITING
				if thread_info.getThreadState() == Thread.State.TIMED_WAITING:
					timed_waiting_count += 1
		
		# Write the counts to the specified tags
	system.tag.write('[default]Dashboard/Threads/WebserverThreadCount', webserver_count)
	system.tag.write('[default]Dashboard/Threads/TIMED_WAITING', timed_waiting_count)

```

So it's working fine from the button but not from the gateway event script with a 10,000 ms timer.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/1/b/1bda6660e8cb6ba84e9d2d3706c07f8ab9d9767f.png)

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [April 29, 2024, 7:20pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/14 "2024-04-29T19:20:09Z")

</div>

I made a simple library script:

```python
from java.lang.management import ManagementFactory
from java.lang import Thread
from com.inductiveautomation.ignition.common.util import SimplePatternSearcher

RUNNABLE = Thread.State.RUNNABLE
BLOCKED = Thread.State.BLOCKED
WAITING = Thread.State.WAITING
TIMED_WAITING = Thread.State.TIMED_WAITING
TERMINATED = Thread.State.TERMINATED

def get_threads(state=None, name_filter=None):
	thread_mx_bean = ManagementFactory.getThreadMXBean()
	thread_ids = thread_mx_bean.allThreadIds
	threads = thread_mx_bean.getThreadInfo(thread_ids)
	if state is not None:
		if isinstance(state, basestring):
			state = Thread.State.valueOf(state.upper())
		threads = filter(lambda info: info.threadState == state, threads)

	if name_filter is not None:
		pattern = SimplePatternSearcher(name_filter)
		threads = filter(lambda info: pattern.matches(info.threadName), threads)
	return threads

```

The 'SimplePatternSearcher' supports `*` and `?` wildcards for multiple or single character replacements, and is inherently case insensitive.

```python
print len(threads.get_threads(threads.TIMED_WAITING))
print len(threads.get_threads(state="TIMED_WAITING"))

print threads.get_threads(name_filter="swing*")

```

---

<div class="post-metadata">

**Author:** ![hw79](https://avatars.discourse-cdn.com/v4/letter/h/838e76/32.png) [@hw79](https://forum.inductiveautomation.com/u/hw79)\
**Post date:** [April 29, 2024, 7:25pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/15 "2024-04-29T19:25:40Z")

</div>

Thanks, I figured out what happened.

On the gateway script I had it wrapped in a function but imported the java stuff from outside the function.

Thanks for all your help!

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [April 29, 2024, 9:57pm UTC](https://forum.inductiveautomation.com/t/getting-threads-from-the-gateway/89447/16 "2024-04-29T21:57:55Z")

</div>

> [@hw79](#):
>
> On the gateway script I had it wrapped in a function but imported the java stuff from outside the function.

That is legacy behavior in gateway events. One of the reasons I _ **strongly** _ recommend never writing an actual script in the event. Just put a one-liner there that calls a library script function. Library scripts don't have the funky problems with nested scopes.
