java - 在 Java 中生成唯一 ID,以标记日志中的相关条目组

标签 java datetime logging uuid

关于这个主题,有几篇关于 SO 的帖子。每个人都在谈论一种特定的方法,因此只想在一个问题中进行比较。

Using new Date() as unique identifier

Generating a globally unique identifier in Java

我正在尝试实现一项功能,我们可以在其中识别日志文件中的某些事件。这些事件需要与唯一的 id 相关联。
我正在尝试为这种独特的 ID 生成提出一种策略。
ID 必须有 2 个部分:
一些静态信息+一些动态信息
当需要调试事件时,可以在日志中搜索模式。
我有三种方法:

  • 静态信息 + Joda 日期时间("abc"+2014-01-30T12:36:12.703)
  • 静态信息 + 原子整数
  • 静态信息 + UUID

  • 对于这个问题的范围,多个 JVM 不是考虑因素。
    我需要在一个 JVM 上以有效的方式生成唯一 ID。此外,我将无法使用依赖于数据库的解决方案。

    上述 3 种策略中哪一种最有效?
  • 如果不是上述策略,还有其他策略吗?
  • Joda 基于时间的策略是否稳健? JVM 是单一的,但会有并发用户,因此可以有并发事件。
  • 结合上述/其他策略之一,我是否需要使我的方法线程安全/同步?
  • 最佳答案

    我和你有同样的需求,区分日志中与其他无关条目交错的相关条目线程。我已经尝试了您建议的所有三种方法。我的经验是在 4D不是Java,但类似。

    日期时间

    就我而言,我使用的是解析为整秒的日期时间值。这只是一个太大的粒度。我很容易在同一秒内开始发生多个事件的冲突。该死的那些高速电脑!

    在您使用捆绑的 java.util.Date 或 Joda-Time 的情况下(强烈推荐用于其他目的),两者都解析为毫秒。一毫秒在现代计算机中是很长的时间,所以我不推荐这样做。

    在 Java 8 中,新的 java.time.* package (受 Joda-Time 的启发,由 JSR 310 定义)解析为纳秒。这似乎是一个更好的标识符,但不是。一方面,您计算机的物理计时时钟可能不支持如此精细的分辨率。另一个是计算机越来越快。最后,计算机的时钟可以重置,实际上它经常被重置,因为计算机时钟漂移了很多。现代操作系统通过频繁检查 time server 来重置他们的时钟在本地或通过 Internet。

    此外,日志已经有了时间戳,因此使用日期时间作为我们的标识符并没有得到任何额外的好处。事实上,在日志条目中有第二个日期时间实际上可能会引起混淆。

    序列号

    通过“原子整数”,我假设您的意思是序列号增加到增加的数字。

    这对于您的目的来说似乎有点过分。

  • 您不关心顺序,它对分组日志条目的这个目的没有意义。您并不真正关心一组是在另一组之前还是之后出现第 n 个数字。
  • 保持序列是一种痛苦,是潜在的失败点。我总是最终遇到维护序列的管理问题。

  • 因此,这种方法增加了风险,而没有增加任何特殊的好处。

    用户名

    宾果!正是您所需要的。

    UUID很容易生成,使用捆绑的 java.util.UUID 类的能力生成版本 3 或 4 UUID,或使用第三方库,或访问命令行的 uuidgen工具。

    对于非常大的容量,[版本 1] UUID ( MAC + 日期时间 + 随机数) 将是最好的。对于日志记录,一个 Version 4 UUID(完全随机)是绝对可以接受的。

    发生碰撞并不是一个现实的问题。特别是对于为日志生成的有限数量的值。我很惊讶那些无法理解数字的人说他们永远不会用 UUID 替换序列。然而,当我按下时,我认识的每一位程序员和系统管理员都经历过至少一个序列的失败。

    无需担心线程安全。无需担心争用(请参阅我在 another answer of mine 上的测试结果)。

    UUID 的另一个好处是它通常的 hexadecimal代表,例如:

    6536ca53-bcad-4552-977f-16945fee13e2



    ……很容易辨认。识别后,读者立即知道该字符串是唯一标识符。所以它在你的日志中的存在是自我记录的。

    我发现 UUID 是计算的管道胶带。我一直在寻找它们的新用途。

    因此,在相关代码的开头,生成一个 UUID,然后将其嵌入到每个相关的日志条目中。

    虽然 UUID 的十六进制字符串表示很难读写,但实际上您只需要扫描开头或结尾的几个数字。或者在我们的现代控制台工具中使用带有搜索和过滤功能的复制粘贴。

    一些事实
  • UUID 在 Microsoft 世界中被称为 GUID .
  • UUID 不是字符串,而是 128 位值。位,只是内存中的位,“开”/“关”值。一些数据库,如 Postgres ,知道如何将 UUID 处理和存储为 128 位值。如果我们希望向人类展示这些位,我们可以使用一系列 128 位的“1”和“0”。但是人类在试图读写 128 位 1 和 0 时表现不佳。所以我们使用十六进制表示。但即使是 32 个十六进制数字对人类来说也太多了,所以我们将字符串分成几组,用连字符分隔,如上所示,总共 36 个字符。
  • UUID 的规范非常清楚,十六进制表示应该是 小写 .规范说从字符串输入创建 UUID 时,应该容忍大写。但是在生成十六进制字符串时,它应该是小写的。 UUID 的许多实现忽略了这个要求。我建议坚持规范并将您的 UUID 十六进制字符串转换为小写。

  • MDC – 映射诊断上下文

    我还没有使用过 MDC,但想指出它......

    一些日志框架正在添加对这种标记相关日志条目的想法的支持。这种支持称为映射诊断上下文 (MDC)。 MDC 基于每个线程管理上下文信息。

    一篇快速介绍性文章是 Log4j MDC (Mapped Diagnostic Context) : What and Why .

    最好的伐木立面,SLF4J , 提供此类 an MDC feature .该外观的最佳实现,Logback , 有一个 chapter documenting its MDC feature .

    关于java - 在 Java 中生成唯一 ID,以标记日志中的相关条目组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21536572/

    相关文章:

    java - 如何在 Spring boot 中的 appication.properties 中启用 undertow 日志

    java - 如何在测试中覆盖单个应用程序属性

    c# - 如何让天数在范围内

    date - Google Calendar API 不接受具有正 UTC 偏移量的日期时间?

    python - 两列到一列的值差异

    php - 简单记录到 php 的数据库类/工具包?

    我可以获得指向当前函数的指针吗?

    加载外部 Jar(插件架构)时 JavaFX 样式丢失

    java - 如何将 Intent 数据设置为当前 Activity editText?

    java.lang.OutOfMemory错误: Failed to allocate a 571401228 byte allocation with 16777216 free bytes and 495MB until OOM