Juniper Mist Monitoring
Last updated - 25 July, 2025
In this article
LogicMonitor offers monitoring for Juniper Mist organizations, sites, and devices. You can monitor organization health, sites and traffic generated by the sites, as well as Juniper Mist-managed devices such as Juniper Mist Access Points, EX-Series Switches, Session and Smart Routers. The Juniper Mist API is used to retrieve site device stats and data.
Requirements
- Install or update the Juniper Mist LogicModules.
- Verify that you have Collector version 32.400 or higher installed.
- An API Token and Mist Organization ID using the Juniper Mist portal or Juniper Mist API. For more information, see Create API Token and How do I find my Org and Site ID?
Adding Juniper Mist Resources
You can add Juniper Mist resources by using the following methods:
- (Recommended) Advanced NetScan that creates devices under device groups for each Mist organization site. For more information, see What is NetScan.
- Manually
Using Advanced NetScan to add Juniper Mist Resources (Recommended )
- Navigate to Device Credentials > Use custom credentials for this scan, use the following properties:
Property | Value |
mist.api.key | Mist API token |
mist.api.org | Mist Organization ID |
mist.api.org.name | Display name of your Mist device group folder, defaults to “Mist Organization” |
- When configuring the Enhanced Script Netscan, use Embed Groovy Script and use the following script:
Warning: Do not edit the script. Edited Enhanced Script NetScans are not supported. If the LogicMonitor-provided script is edited, LogicMonitor Support may (at their discretion) require you to overwrite your edits with the supported script if problems arise.
/*******************************************************************************
* © 2007-2024 - LogicMonitor, Inc. All rights reserved.
******************************************************************************/
import com.logicmonitor.common.sse.utils.GroovyScriptHelper as GSH
import com.logicmonitor.mod.Snippets
import com.santaba.agent.util.Settings
import com.santaba.agent.AgentVersion
import groovy.json.JsonSlurper
import java.text.DecimalFormat
// To run in debug mode, set to true
Boolean debug = false
// To enable logging, set to true
Boolean log = false
// Set props object based on whether or not we are running inside a netscan or debug console
def props
try {
hostProps.get("system.hostname")
props = hostProps
debug = true // set debug to true so that we can ensure we do not print sensitive properties
}
catch (MissingPropertyException) {
props = netscanProps
}
String organization = props.get("mist.api.org")
String token = props.get("mist.api.key")
if (!organization) {
throw new Exception("Must provide mist.api.org to run this script. Verify necessary credentials have been provided in Netscan properties.")
}
if (!token) {
throw new Exception("Must provide mist.api.key credentials to run this script. Verify necessary credentials have been provided in Netscan properties.")
}
def logCacheContext = "${organization}::juniper-mist"
Boolean skipDeviceDedupe = props.get("skip.device.dedupe", "false").toBoolean()
String hostnameSource = props.get("hostname.source", "")?.toLowerCase()?.trim()
Integer collectorVersion = AgentVersion.AGENT_VERSION.toInteger()
// Bail out early if we don't have the correct minimum collector version to ensure netscan runs properly
if (collectorVersion < 32400) {
def formattedVer = new DecimalFormat("00.000").format(collectorVersion / 1000)
throw new Exception("Upgrade collector running netscan to 32.400 or higher to run full featured enhanced netscan. Currently running version ${formattedVer}.")
}
def modLoader = GSH.getInstance()._getScript("Snippets", Snippets.getLoader()).withBinding(getBinding())
def emit = modLoader.load("lm.emit", "0")
def lmDebugSnip = modLoader.load("lm.debug", "1")
def lmDebug = lmDebugSnip.debugSnippetFactory(out, debug, log, logCacheContext)
def httpSnip = modLoader.load("proto.http", "0")
def http = httpSnip.httpSnippetFactory(props)
def cacheSnip = modLoader.load("lm.cache", "0")
def cache = cacheSnip.cacheSnippetFactory(lmDebug, logCacheContext)
// Only initialize lmApi snippet class if customer has not opted out
def lmApi
if (!skipDeviceDedupe) {
def lmApiSnippet = modLoader.load("lm.api", "0")
lmApi = lmApiSnippet.lmApiSnippetFactory(props, http, lmDebug)
}
def juniperMistSnip = modLoader.load("juniper.mist", "0")
def juniperMist = juniperMistSnip.juniperMistSnippetFactory(props, lmDebug, cache, http)
String url = props.get("mist.api.url")?.trim() ?: "https://api.mist.com/api/v1/"
if (!url.endsWith("/")) url += "/"
String organizationDisplayname = props.get("mist.api.org.name")?.trim() ?: "MistOrganization"
String organizationFolder = props.get("mist.api.org.folder")?.trim() ? props.get("mist.api.org.folder") + "/" : ""
def sitesWhitelist = props.get("mist.api.org.sites")?.tokenize(",")?.collect{ it.trim() }
def collectorSitesCSV = props.get("mist.api.org.collector.sites.csv")
def collectorSiteInfo
if (collectorSitesCSV) {
collectorSiteInfo = processCollectorSiteInfoCSV(collectorSitesCSV)
}
Map headers = ["Authorization":"token ${token}", "Accept":"application/json"]
List<Map> resources = []
def organizationSites = juniperMist.http.rawGet("${url}orgs/${organization}/sites", headers)
if (organizationSites) {
organizationSites = juniperMist.slurper.parseText(organizationSites.content.text)
organizationSites.each { organizationSite ->
def siteName = organizationSite.get("name")
if (sitesWhitelist != null && !sitesWhitelist.contains(siteName)) return
def site = organizationSite.get("id")
def siteDeviceStats = juniperMist.http.rawGet("${url}sites/${site}/stats/devices?type=all", headers)
if (siteDeviceStats) {
siteDeviceStats = juniperMist.slurper.parseText(siteDeviceStats.content.text)
siteDeviceStats.each { siteDeviceStat ->
def ip = siteDeviceStat.get("ip")
def name = siteDeviceStat.get("name")
def type = siteDeviceStat.get("type")
def deviceProps = ["mist.api.org": organization, "mist.api.site": site, "mist.device.type": type, "mist.api.org.site.name": siteName, "mist.api.key": token]
if (sitesWhitelist != null) deviceProps.put("mist.api.org.sites", props.get("mist.api.org.sites"))
if (type == "ap") {
deviceProps.put("system.categories", "JuniperMistAP,NoPing")
} else if (type == "switch") {
deviceProps.put("system.categories", "JuniperMistSwitch")
} else if (type == "gateway") {
deviceProps.put("system.categories", "JuniperMistGateway")
if (siteDeviceStat.module_stat && siteDeviceStat.module2_stat) {
def primaryNodeIndex = siteDeviceStat.module_stat.node_name.get(0)
def secondaryNodeIndex = siteDeviceStat.module2_stat.node_name.get(0)
if (collectorSiteInfo) {
def collectorIdEntry = collectorSiteInfo.find{ it.contains(siteName) }
def collectorId = collectorIdEntry[0]
def folder = collectorIdEntry[2]
Map resource = [
"hostname" : "${ip}-${secondaryNodeIndex}",
"displayname" : "${name}-${secondaryNodeIndex}",
"hostProps" : deviceProps,
"groupName" : ["${organizationFolder}${folder}/${siteName}"],
"collectorId" : collectorId
]
resources.add(resource)
} else {
Map resource = [
"hostname" : "${ip}-${secondaryNodeIndex}",
"displayname" : "${name}-${secondaryNodeIndex}",
"hostProps" : deviceProps,
"groupName" : ["${organizationFolder}${organizationDisplayname}/${siteName}"]
]
resources.add(resource)
}
name = "${name}-${primaryNodeIndex}"
}
}
if (ip && name && type && siteName) {
if (ip.contains("127.0.0.1")) ip = name
if (collectorSiteInfo) {
def collectorIdEntry = collectorSiteInfo.find{ it.contains(siteName) }
def collectorId = collectorIdEntry[0]
def folder = collectorIdEntry[2]
Map resource = [
"hostname" : ip,
"displayname" : name,
"hostProps" : deviceProps,
"groupName" : ["${organizationFolder}${folder}/${siteName}"],
"collectorId" : collectorId
]
resources.add(resource)
} else {
Map resource = [
"hostname" : ip,
"displayname" : name,
"hostProps" : deviceProps,
"groupName" : ["${organizationFolder}${organizationDisplayname}/${siteName}"]
]
resources.add(resource)
}
}
}
} else {
throw new Exception("Error occurred during sites/${site}/stats/devices?type=all HTTP GET: ${siteDeviceStats}.")
}
}
emit.resource(resources)
} else {
throw new Exception("Error occurred during orgs/${organization}/sites HTTP GET: ${organizationSites}.")
}
return 0
// Helper function to process a collector id, site organization device name, folder, and site CSV
def processCollectorSiteInfoCSV(String filename) {
// Ensure relative filepath is complete with extension type
def filepath
if (!filename.contains("./")) {
filepath = "./${filename}"
}
if (!filename.contains(".csv")) {
filepath = "${filename}.csv"
}
// Read file into memory and split into list of lists
def csv = new File(filepath)
def rows = csv.readLines()*.split(",")
def data
// Verify whether headers are present and expected values
// Sanitize for casing and extra whitespaces while gathering headers
def maybeHeaders = rows[0]*.toLowerCase()*.trim()
if (maybeHeaders.contains("collector id") && maybeHeaders.contains("site organization device name") && maybeHeaders.contains("folder") && maybeHeaders.contains("site")) {
// Remove headers from dataset
data = rows[1..-1]
}
// Bail out early if we don't have the expected headers in the provided CSV
else {
throw new Exception(" Required headers not provided in CSV. Please provide \"Collector ID\", \"Site Organization Device Name\", \"Folder\", and \"Site\" (case insensitive). Headers provided: \"${rows[0]}\"")
}
return data
}
Manually Adding Juniper Mist Resources
- Create a Juniper Mist Organization device group. For more information, see Adding Device Groups.
Property | Value |
mist.api.org | Mist Organization ID |
- Add the devices to the Mist Organization device group under a Site device group with the following property added. For more information, see How do I find my Org and Site ID?
Property | Value |
mist.api.site | Mist Site ID |
mist.api.key | API key |
Juniper Mist Properties
Additional attributes and values for Juniper Mist.
Proxy Settings
The modules in this suite support HTTP connections using a proxy server. You can configure this in the Collector settings, see Configuring your Collector for use with HTTP Proxies, or with the following device host properties. Device host properties take precedence over Collector settings for proxy configurations.
Property | Value |
proxy.enable | (Optional) This suite is written to use collector proxy settings for HTTP calls configured by the user. To enable, add this device property with the value set to true. Set to false to override the use of configured collector proxy settings and connect without a proxy. |
proxy.host | (Optional) Configure a proxy host to connect through that is different from collector configuration. |
proxy.port | (Optional) Configure a proxy port to connect through that is different from collector configuration. |
Mapping Mist Sites to LM Envision Collectors
Collector ID | Site Organization Device Name | Folder | Sites |
11 | Region_East_Sites | Region_East | NYC |
11 | Region_East_Sites | Region_East | MIA |
11 | Region_East_Sites | Region_East | CLT |
11 | Region_East_Sites | Region_East | ATL |
11 | Region_East_Sites | Region_East | BOS |
11 | Region_East_Sites | Region_East | CHS |
1 | Region_West_Sites | Region_West | LAX |
1 | Region_West_Sites | Region_West | LAS |
1 | Region_West_Sites | Region_West | SEA |
Comma-separated values for Collector ID, Site Organization Device Name, Folder, and Sites.
Collector ID,Site Organization Device Name,Folder,Sites
11,Region_East_Sites,Region_East,NYC
11,Region_East_Sites,Region_East,MIA
11,Region_East_Sites,Region_East,CLT
11,Region_East_Sites,Region_East,ATL
11,Region_East_Sites,Region_East,BOS
11,Region_East_Sites,Region_East,CHS
1,Region_West_Sites,Region_West,LAX
1,Region_West_Sites,Region_West,LAS
1,Region_West_Sites,Region_West,SEA
Juniper Mist Troubleshooting
- This suite relies on collector script cache to continuously retrieve and store data from the Juniper Mist API to minimize rate limiting constraints. For more information, see Collector Script Caching. Continuous data collection is maintained through the
Juniper_Mist_API
DataSource, which writes API responses to the collector script cache.Juniper_Mist_API
DataSource must be running successfully for all other modules in this package to be successful. - During onboarding, you can run Active Discovery manually on additional PropertySources in this package after
Juniper_Mist_API
begins collecting data to expedite monitoring and topology mapping. - If data gaps exist, verify
Juniper_Mist_API
is functioning successfully and check script cache health in theLogicMonitor_Collector_ScriptCache
DataSource.
Note: The API used to pull data has rate limits. Check Juniper_Mist_API on your Mist Organization device in order to check if the API is unreachable or monitoring has hit the API rate limit.
LogicModules in Package
LogicMonitor’s package for Juniper Mist consists of the following LogicModules. For full coverage, ensure that all of these LogicModules are imported into your LogicMonitor platform:
Display Name | Type | Description |
Juniper_Mist_Topology | TopologySource | Topology of a Mist Org. Sites, and managed-devices. |
Mist AP Beacons | DataSource | Health and performance of Mist-managed AP Beacons. |
Mist AP Health | DataSource | Health and availability of Juniper Mist-managed wireless access points. |
Mist AP Interfaces | DataSource | Status and network transmission and receive statistics for Juniper Mist-managed AP interfaces. |
Mist AP Performance | DataSource | Performance of Juniper Mist-managed wireless access points. |
Mist AP Radios | DataSource | Mist-managed AP radio power and usage. |
Mist API | DataSource | Health of the monitored Mist Organization and the Mist API connection. |
Mist Switch Performance | DataSource | Performance of Mist-managed switches. |
Mist Switch Health | DataSource | Health of Mist-managed switches. |
Mist WAN Edge Performance | DataSource | Performance of Mist-managed session smart routers. |
Mist WAN Edge Health | DataSource | Health of Mist-managed session smart routers. |
addCategory_Juniper_Mist_Device | PropertySource | Adds the JuniperMist<device type> system.category to devices managed by Juniper Mist Requires Juniper_Mist_Org DataSource (watchdog) in order to collect data. |
addERI_Juniper_Mist_Device | PropertySource | Sets Juniper Mist device MAC address ERI and device type ERT. Requires Juniper_Mist_Org DataSource (watchdog) in order to collect data. |
When setting static datapoint thresholds on the various metrics tracked by this package’s DataSources, LogicMonitor follows the technology owner’s best practice KPI recommendations.
Recommendation:As necessary, adjust these predefined thresholds to meet the unique needs of your environment. For more information on tuning datapoint thresholds, see Tuning Static Thresholds for Datapoints.