LogEntry.kt 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * Nextcloud Android client application
  3. *
  4. * @author Chris Narkiewicz
  5. * Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Affero General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. package com.nextcloud.client.logger
  21. import java.text.ParseException
  22. import java.text.SimpleDateFormat
  23. import java.util.Date
  24. import java.util.Locale
  25. import java.util.TimeZone
  26. data class LogEntry(val timestamp: Date, val level: Level, val tag: String, val message: String) {
  27. companion object {
  28. private const val UTC_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
  29. private const val TZ_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
  30. private val TIME_ZONE = TimeZone.getTimeZone("UTC")
  31. private val DATE_GROUP_INDEX = 1
  32. private val LEVEL_GROUP_INDEX = 2
  33. private val TAG_GROUP_INDEX = 3
  34. private val MESSAGE_GROUP_INDEX = 4
  35. /**
  36. * <iso8601 date>;<level tag>;<entry tag>;<message>
  37. * 1970-01-01T00:00:00.000Z;D;tag;some message
  38. */
  39. private val ENTRY_PARSE_REGEXP = Regex(
  40. pattern = """(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z);([ADEIVW]);([^;]+);(.*)"""
  41. )
  42. @JvmStatic
  43. fun buildDateFormat(tz: TimeZone? = null): SimpleDateFormat {
  44. return if (tz == null) {
  45. SimpleDateFormat(UTC_DATE_FORMAT, Locale.US).apply {
  46. timeZone = TIME_ZONE
  47. isLenient = false
  48. }
  49. } else {
  50. SimpleDateFormat(TZ_DATE_FORMAT, Locale.US).apply {
  51. timeZone = tz
  52. isLenient = false
  53. }
  54. }
  55. }
  56. @Suppress("ReturnCount")
  57. @JvmStatic
  58. fun parse(s: String): LogEntry? {
  59. val result = ENTRY_PARSE_REGEXP.matchEntire(s) ?: return null
  60. val date = try {
  61. buildDateFormat().parse(result.groupValues[DATE_GROUP_INDEX])
  62. } catch (ex: ParseException) {
  63. return null
  64. }
  65. val level: Level = Level.fromTag(result.groupValues[LEVEL_GROUP_INDEX])
  66. val tag = result.groupValues[TAG_GROUP_INDEX]
  67. val message = result.groupValues[MESSAGE_GROUP_INDEX].replace("\\n", "\n")
  68. return LogEntry(
  69. timestamp = date,
  70. level = level,
  71. tag = tag,
  72. message = message
  73. )
  74. }
  75. }
  76. override fun toString(): String {
  77. val sb = StringBuilder()
  78. format(sb, buildDateFormat())
  79. return sb.toString()
  80. }
  81. fun toString(tz: TimeZone): String {
  82. val sb = StringBuilder()
  83. format(sb, buildDateFormat(tz))
  84. return sb.toString()
  85. }
  86. private fun format(sb: StringBuilder, dateFormat: SimpleDateFormat) {
  87. sb.append(dateFormat.format(timestamp))
  88. sb.append(';')
  89. sb.append(level.tag)
  90. sb.append(';')
  91. sb.append(tag.replace(';', ' '))
  92. sb.append(';')
  93. sb.append(message.replace("\n", "\\n"))
  94. }
  95. }