importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importjava.net.InetAddress;importjava.net.UnknownHostException;importjava.util.Random;publicclassIdGenerator{privatestaticfinalLoggerlogger=LoggerFactory.getLogger(IdGenerator.class);publicstaticStringgenerate(){Stringid="";try{StringhostName=InetAddress.getLocalHost().getHostName();String[]tokens=hostName.split("\\.");if(tokens.length>0){hostName=tokens[tokens.length-1];}char[]randomChars=newchar[8];intcount=0;Randomrandom=newRandom();while(count<8){intrandomAscii=random.nextInt(122);if(randomAscii>=48&&randomAscii<=57){randomChars[count]=(char)('0'+(randomAscii-48));count++;}elseif(randomAscii>=65&&randomAscii<=90){randomChars[count]=(char)('A'+(randomAscii-65));count++;}elseif(randomAscii>=97&&randomAscii<=122){randomChars[count]=(char)('a'+(randomAscii-97));count++;}}id=String.format("%s-%d-%s",hostName,System.currentTimeMillis(),newString(randomChars));}catch(UnknownHostExceptione){logger.warn("Failed to get the host name.",e);}returnid;}}
我们可以看到整个 ID 由三部分组成。第一部分是本机名的最后一个字段。第二部分是当前时间戳,精确到毫秒。第三部分是 8 位的随机字符串,包含大小写字母和数字。尽管这样生成的 ID 并不是绝对唯一的,有重复的可能,但事实上重复的概率非常低。对于我们的日志追踪来说,极小概率的 ID 重复是完全可以接受的。
publicinterfaceIdGenerator{Stringgenerate();}publicinterfaceLogTraceIdGeneratorextendsIdGenerator{}publicclassRandomIdGeneratorimplementsLogTraceIdGenerator{privatestaticfinalLoggerlogger=LoggerFactory.getLogger(RandomIdGenerator.class);@OverridepublicStringgenerate(){StringsubstrOfHostName=getLastfieldOfHostName();longcurrentTimeMillis=System.currentTimeMillis();StringrandomString=generateRandomAlphameric(8);Stringid=String.format("%s-%d-%s",substrOfHostName,currentTimeMillis,randomString);returnid;}privateStringgetLastfieldOfHostName(){StringsubstrOfHostName=null;try{StringhostName=InetAddress.getLocalHost().getHostName();String[]tokens=hostName.split("\\.");substrOfHostName=tokens[tokens.length-1];returnsubstrOfHostName;}catch(UnknownHostExceptione){logger.warn("Failed to get the host name.",e);}returnsubstrOfHostName;}privateStringgenerateRandomAlphameric(intlength){char[]randomChars=newchar[length];intcount=0;Randomrandom=newRandom();while(count<length){intmaxAscii='z';intrandomAscii=random.nextInt(maxAscii);booleanisDigit=randomAscii>='0'&&randomAscii<='9';booleanisUppercase=randomAscii>='A'&&randomAscii<='Z';booleanisLowercase=randomAscii>='a'&&randomAscii<='z';if(isDigit||isUppercase||isLowercase){randomChars[count]=(char)(randomAscii);++count;}}returnnewString(randomChars);}}//代码使用举例
LogTraceIdGeneratorlogTraceIdGenerator=newRandomIdGenerator();
publicclassRandomIdGeneratorimplementsLogTraceIdGenerator{privatestaticfinalLoggerlogger=LoggerFactory.getLogger(RandomIdGenerator.class);@OverridepublicStringgenerate(){StringsubstrOfHostName=getLastfieldOfHostName();longcurrentTimeMillis=System.currentTimeMillis();StringrandomString=generateRandomAlphameric(8);Stringid=String.format("%s-%d-%s",substrOfHostName,currentTimeMillis,randomString);returnid;}privateStringgetLastfieldOfHostName(){StringsubstrOfHostName=null;try{StringhostName=InetAddress.getLocalHost().getHostName();substrOfHostName=getLastSubstrSplittedByDot(hostName);}catch(UnknownHostExceptione){logger.warn("Failed to get the host name.",e);}returnsubstrOfHostName;}@VisibleForTestingprotectedStringgetLastSubstrSplittedByDot(StringhostName){String[]tokens=hostName.split("\\.");StringsubstrOfHostName=tokens[tokens.length-1];returnsubstrOfHostName;}@VisibleForTestingprotectedStringgenerateRandomAlphameric(intlength){char[]randomChars=newchar[length];intcount=0;Randomrandom=newRandom();while(count<length){intmaxAscii='z';intrandomAscii=random.nextInt(maxAscii);booleanisDigit=randomAscii>='0'&&randomAscii<='9';booleanisUppercase=randomAscii>='A'&&randomAscii<='Z';booleanisLowercase=randomAscii>='a'&&randomAscii<='z';if(isDigit||isUppercase||isLowercase){randomChars[count]=(char)(randomAscii);++count;}}returnnewString(randomChars);}}
/**
* Id Generator that is used to generate random IDs.
*
* <p>
* The IDs generated by this class are not absolutely unique,
* but the probability of duplication is very low.
*/publicclassRandomIdGeneratorimplementsLogTraceIdGenerator{privatestaticfinalLoggerlogger=LoggerFactory.getLogger(RandomIdGenerator.class);/**
* Generate the random ID. The IDs may be duplicated only in extreme situation.
*
* @return an random ID
*/@OverridepublicStringgenerate(){//...
}/**
* Get the local hostname and
* extract the last field of the name string splitted by delimiter '.'.
*
* @return the last field of hostname. Returns null if hostname is not obtained.
*/privateStringgetLastfieldOfHostName(){//...
}/**
* Get the last field of {@hostName} splitted by delemiter '.'.
*
* @param hostName should not be null
* @return the last field of {@hostName}. Returns empty string if {@hostName} is empty string.
*/@VisibleForTestingprotectedStringgetLastSubstrSplittedByDot(StringhostName){//...
}/**
* Generate random string which
* only contains digits, uppercase letters and lowercase letters.
*
* @param length should not be less than 0
* @return the random string. Returns empty string if {@length} is 0
*/@VisibleForTestingprotectedStringgenerateRandomAlphameric(intlength){//...
}}