Beispiel #1
0
// Satisfy the LineFormatter interface. Formats the StatLines as a grid.
func (glf *GridLineFormatter) FormatLines(lines []StatLine, index int, discover bool) string {
	buf := &bytes.Buffer{}

	// Automatically turn on discover-style formatting if more than one host's
	// output is being displayed (to include things like hostname column)
	discover = discover || len(lines) > 1

	if discover {
		glf.Writer.WriteCell(" ")
	}

	lineFlags := getLineFlags(lines)

	// Sort the stat lines by hostname, so that we see the output
	// in the same order for each snapshot
	sort.Sort(StatLines(lines))

	// Print the columns that are enabled
	for _, header := range StatHeaders {
		maskedAttrs := lineFlags & header.ActivateFlags
		// Only show the header if this column has the "Always" flag, or all
		// other flags for this column are matched
		if (maskedAttrs&Always == 0) && maskedAttrs != header.ActivateFlags {
			continue
		}

		// Don't write any cell content for blank headers, since they act as placeholders
		if len(header.HeaderText) > 0 {
			glf.Writer.WriteCell(header.HeaderText)
		}
	}
	glf.Writer.EndRow()

	for _, line := range lines {

		mmap := line.StorageEngine == "mmapv1"

		if discover {
			glf.Writer.WriteCell(line.Key)
		}
		if line.Error != nil {
			glf.Writer.Feed(line.Error.Error())
			continue
		}

		// Write the opcount columns (always active)
		glf.Writer.WriteCell(formatOpcount(line.Insert, line.InsertR, false))
		glf.Writer.WriteCell(formatOpcount(line.Query, line.QueryR, false))
		glf.Writer.WriteCell(formatOpcount(line.Update, line.UpdateR, false))
		glf.Writer.WriteCell(formatOpcount(line.Delete, line.DeleteR, false))
		glf.Writer.WriteCell(fmt.Sprintf("%v", line.GetMore))
		glf.Writer.WriteCell(formatOpcount(line.Command, line.CommandR, true))

		if lineFlags&WTOnly > 0 {
			if line.CacheDirtyPercent < 0 {
				glf.Writer.WriteCell("")
			} else {
				glf.Writer.WriteCell(fmt.Sprintf("%.1f", line.CacheDirtyPercent*100))
			}
			if line.CacheUsedPercent < 0 {
				glf.Writer.WriteCell("")
			} else {
				glf.Writer.WriteCell(fmt.Sprintf("%.1f", line.CacheUsedPercent*100))
			}
		}

		glf.Writer.WriteCell(fmt.Sprintf("%v", line.Flushes))

		// Columns for flushes + mapped only show up if mmap columns are active
		if lineFlags&MMAPOnly > 0 {

			if line.Mapped > 0 {
				glf.Writer.WriteCell(text.FormatMegabyteAmount(int64(line.Mapped)))
			} else {
				//for mongos nodes, Mapped is empty, so write a blank cell.
				glf.Writer.WriteCell("")
			}
		}

		// Columns for Virtual and Resident are always active
		glf.Writer.WriteCell(text.FormatMegabyteAmount(int64(line.Virtual)))
		glf.Writer.WriteCell(text.FormatMegabyteAmount(int64(line.Resident)))

		if lineFlags&MMAPOnly > 0 {
			if lineFlags&AllOnly > 0 {
				nonMappedVal := ""
				if line.NonMapped >= 0 { // not mongos, update accordingly
					nonMappedVal = text.FormatMegabyteAmount(int64(line.NonMapped))
				}
				glf.Writer.WriteCell(nonMappedVal)
			}
			if mmap {
				glf.Writer.WriteCell(fmt.Sprintf("%v", line.Faults))
			} else {
				glf.Writer.WriteCell("n/a")
			}
		}

		if lineFlags&MMAPOnly > 0 && lineFlags&AllOnly > 0 {
			// check if we have any locks
			if lineFlags&Locks <= 0 {
				if line.CollectionLocks != nil && !line.IsMongos {
					percentCell := fmt.Sprintf("%.1f%%|%.1f%%", line.CollectionLocks.ReadAcquireWaitsPercentage,
						line.CollectionLocks.WriteAcquireWaitsPercentage)
					glf.Writer.WriteCell(percentCell)
					timeCell := fmt.Sprintf("%v|%v", line.CollectionLocks.ReadAcquireTimeMicros,
						line.CollectionLocks.WriteAcquireTimeMicros)
					glf.Writer.WriteCell(timeCell)
				} else {
					//don't write any lock status for mongos nodes
					glf.Writer.WriteCell("")
					glf.Writer.WriteCell("")
				}
			} else {
				// no locks
				glf.Writer.WriteCell("n/a")
				glf.Writer.WriteCell("n/a")
			}
		}

		// Write columns related to lock % if activated
		if lineFlags&Locks > 0 {
			if line.HighestLocked != nil && !line.IsMongos {
				lockCell := fmt.Sprintf("%v:%.1f", line.HighestLocked.DBName,
					line.HighestLocked.Percentage) + "%"
				glf.Writer.WriteCell(lockCell)
			} else {
				//don't write any lock status for mongos nodes
				glf.Writer.WriteCell("")
			}
		}
		glf.Writer.WriteCell(fmt.Sprintf("%v|%v", line.QueuedReaders, line.QueuedWriters))
		glf.Writer.WriteCell(fmt.Sprintf("%v|%v", line.ActiveReaders, line.ActiveWriters))

		glf.Writer.WriteCell(text.FormatBits(line.NetIn))
		glf.Writer.WriteCell(text.FormatBits(line.NetOut))

		glf.Writer.WriteCell(fmt.Sprintf("%v", line.NumConnections))
		if discover || lineFlags&Repl > 0 { //only show these fields when in discover or repl mode.
			glf.Writer.WriteCell(line.ReplSetName)
			glf.Writer.WriteCell(line.NodeType)
		}

		glf.Writer.WriteCell(fmt.Sprintf("%v", line.Time.Format("2006-01-02T15:04:05Z07:00")))
		glf.Writer.EndRow()
	}
	glf.Writer.Flush(buf)

	// clear the flushed data
	glf.Writer.Reset()

	returnVal := buf.String()

	if !glf.IncludeHeader || index%glf.HeaderInterval != 0 {
		// Strip out the first line of the formatted output,
		// which contains the headers. They've been left in up until this point
		// in order to force the formatting of the columns to be wide enough.
		firstNewLinePos := strings.Index(returnVal, "\n")
		if firstNewLinePos >= 0 {
			returnVal = returnVal[firstNewLinePos+1:]
		}
	}

	if len(lines) > 1 {
		// For multi-node stats, add an extra newline to tell each block apart
		return "\n" + returnVal
	}
	return returnVal
}
Beispiel #2
0
// Satisfy the LineFormatter interface. Formats the StatLines as JSON.
func (jlf *JSONLineFormatter) FormatLines(lines []StatLine, index int, discover bool) string {

	lineFlags := getLineFlags(lines)

	// middle ground b/t the StatLines and the JSON string to be returned
	jsonFormat := map[string]interface{}{}

	// convert each StatLine to JSON
	for _, line := range lines {
		// each line can just be a string->string map (header->value)
		lineJson := map[string]string{}

		// check for error
		if line.Error != nil {
			lineJson["error"] = line.Error.Error()
			jsonFormat[line.Key] = lineJson
			continue
		}

		// put all the appropriate values into the stat line's JSON representation
		lineJson["insert"] = formatOpcount(line.Insert, line.InsertR, false)
		lineJson["query"] = formatOpcount(line.Query, line.QueryR, false)
		lineJson["update"] = formatOpcount(line.Update, line.UpdateR, false)
		lineJson["delete"] = formatOpcount(line.Delete, line.DeleteR, false)
		lineJson["getmore"] = fmt.Sprintf("%v", line.GetMore)
		lineJson["command"] = formatOpcount(line.Command, line.CommandR, true)
		lineJson["netIn"] = text.FormatBits(line.NetIn)
		lineJson["netOut"] = text.FormatBits(line.NetOut)
		lineJson["conn"] = fmt.Sprintf("%v", line.NumConnections)
		lineJson["time"] = fmt.Sprintf("%v", line.Time.Format("15:04:05"))
		lineJson["host"] = line.Host
		lineJson["vsize"] = text.FormatMegabyteAmount(int64(line.Virtual))
		lineJson["res"] = text.FormatMegabyteAmount(int64(line.Resident))

		// add mmapv1-specific fields
		if lineFlags&MMAPOnly > 0 {
			lineJson["flushes"] = fmt.Sprintf("%v", line.Flushes)
			lineJson["qr|qw"] = fmt.Sprintf("%v|%v", line.QueuedReaders,
				line.QueuedWriters)
			lineJson["ar|aw"] = fmt.Sprintf("%v|%v", line.ActiveReaders,
				line.ActiveWriters)

			mappedVal := ""      // empty for mongos
			if line.Mapped > 0 { // not mongos, update accordingly
				mappedVal = text.FormatMegabyteAmount(int64(line.Mapped))
			}
			lineJson["mapped"] = mappedVal

			nonMappedVal := ""       // empty for mongos
			if line.NonMapped >= 0 { // not mongos, update accordingly
				nonMappedVal = text.FormatMegabyteAmount(int64(line.NonMapped))
			}
			lineJson["non-mapped"] = nonMappedVal

			lineJson["faults"] = fmt.Sprintf("%v", line.Faults)

			if lineFlags&AllOnly > 0 {
				// check if we have any locks
				if lineFlags&Locks <= 0 {
					if line.CollectionLocks != nil && !line.IsMongos {
						lineJson["lr|lw %"] = fmt.Sprintf("%.1f%%|%.1f%%", line.CollectionLocks.ReadAcquireWaitsPercentage,
							line.CollectionLocks.WriteAcquireWaitsPercentage)
						lineJson["lrt|lwt"] = fmt.Sprintf("%v|%v", line.CollectionLocks.ReadAcquireTimeMicros,
							line.CollectionLocks.WriteAcquireTimeMicros)
					}
				}
			}

			highestLockedVal := "" // empty for mongos
			if line.HighestLocked != nil && !line.IsMongos {
				highestLockedVal = fmt.Sprintf("%v:%.1f%%",
					line.HighestLocked.DBName, line.HighestLocked.Percentage)
			}
			lineJson["locked"] = highestLockedVal
		}

		if lineFlags&Repl > 0 {
			lineJson["set"] = line.ReplSetName
			lineJson["repl"] = line.NodeType
		}

		// add the line to the final json
		jsonFormat[line.Host] = lineJson
	}

	// convert the JSON format of the lines to a json string to be returned
	linesAsJsonBytes, err := json.Marshal(jsonFormat)
	if err != nil {
		return fmt.Sprintf(`{"json error": "%v"}`, err.Error())
	}

	return string(linesAsJsonBytes) + "\n"
}