예제 #1
0
        private void Process_SingleTokens(string json, JsonToken expected)
        {
            var tokenizer  = new JsonTokenizer();
            int tokenCount = tokenizer.Process(json);

            Assert.Equal(1, tokenCount);
            Assert.Equal(expected, tokenizer.Tokens.Dequeue());
        }
예제 #2
0
        private void Process_TokenSets()
        {
            const int iterations = 10000;

            var data = ProcessTestData_SingleTokens
                       .Select(x => new Tuple <string, JsonToken>((string)x[0], (JsonToken)x[1]))
                       .ToArray();

            var tokenizer = new JsonTokenizer();
            var random    = new Random(0);
            var json      = new StringBuilder();
            var tokens    = new List <JsonToken>();

            for (int run = 0; run < iterations; run++)
            {
                int tokenCount = random.Next(2, 30);

                json.Clear();
                tokens.Clear();
                for (int j = 0; j < tokenCount; j++)
                {
                    int selectedTokenIndex = random.Next(0, data.Length - 1);
                    json.Append(data[selectedTokenIndex].Item1);
                    json.Append(WhiteSpaceCharacters[random.Next(0, WhiteSpaceCharacters.Length - 1)]);
                    tokens.Add(data[selectedTokenIndex].Item2);
                }

                // --- actual test start ---
                int extractedTokenCount = tokenizer.Process(json.ToString());
                Assert.Equal(tokens.Count, extractedTokenCount);
                Assert.Equal(tokens.ToArray(), tokenizer.Tokens.ToArray());

                // --- actual test end ---

                tokenizer.Reset();
            }
        }
        /// <summary>
        /// Processes the specified JSON string and returns the corresponding log messages
        /// (the passed data may contain incomplete JSON documents that are completed over multiple calls).
        /// </summary>
        /// <param name="data">JSON string to process.</param>
        /// <returns>The log messages read from the JSON stream.</returns>
        /// <exception cref="JsonMessageReaderException">Reading the log message failed due to a tokenization, parsing or format error.</exception>
        public ILogMessage[] Process(string data)
        {
            mCompletedLogMessages.Clear();

            int remainingTokenCount;

            try
            {
                remainingTokenCount = mTokenizer.Process(data, false);
            }
            catch (TokenizingException ex)
            {
                // transform exception to ease the interface
                throw new JsonMessageReaderException(
                          ex.LineNumber,
                          ex.Position,
                          ex.Message,
                          ex);
            }

            while (remainingTokenCount-- > 0)
            {
                var token = mTokenizer.Tokens.Dequeue();

                switch (mState)
                {
                case State.Start:
                {
                    if (token.Type != JsonTokenType.LBracket)
                    {
                        ThrowUnexpectedTokenException(ref token);
                    }
                    mStateStack.Push(mState);
                    mState      = State.ReadingObjectKey;
                    mLogMessage = new LogMessage();
                    break;
                }

                case State.ReadingObjectKey:
                {
                    if (token.Type == JsonTokenType.RBracket)
                    {
                        // end of object
                        mState = mStateStack.Pop();
                        if (mState == State.Start)
                        {
                            mCompletedLogMessages.Add(mLogMessage);
                        }
                        break;
                    }

                    if (token.Type == JsonTokenType.String)
                    {
                        // a JSON key
                        if (token.Token == mFieldNames.Timestamp)
                        {
                            mReadingValueState = State.ReadingTimestampValue;
                        }
                        else if (token.Token == mFieldNames.HighPrecisionTimestamp)
                        {
                            mReadingValueState = State.ReadingHighPrecisionTimestampValue;
                        }
                        else if (token.Token == mFieldNames.LogWriter)
                        {
                            mReadingValueState = State.ReadingLogWriterValue;
                        }
                        else if (token.Token == mFieldNames.LogLevel)
                        {
                            mReadingValueState = State.ReadingLogLevelValue;
                        }
                        else if (token.Token == mFieldNames.Tags)
                        {
                            mReadingValueState = State.ReadingTagsValue;
                        }
                        else if (token.Token == mFieldNames.ApplicationName)
                        {
                            mReadingValueState = State.ReadingApplicationNameValue;
                        }
                        else if (token.Token == mFieldNames.ProcessName)
                        {
                            mReadingValueState = State.ReadingProcessNameValue;
                        }
                        else if (token.Token == mFieldNames.ProcessId)
                        {
                            mReadingValueState = State.ReadingProcessIdValue;
                        }
                        else if (token.Token == mFieldNames.Text)
                        {
                            mReadingValueState = State.ReadingTextValue;
                        }
                        else
                        {
                            throw new JsonMessageReaderException(
                                      token.LineNumber,
                                      token.Position,
                                      $"'{token.Token}' at ({token.LineNumber},{token.Position}) is not a valid field name.");
                        }

                        mState = State.ExpectingColon;
                        break;
                    }

                    ThrowUnexpectedTokenException(ref token);
                    break;
                }

                case State.ExpectingColon:
                {
                    if (token.Type != JsonTokenType.Colon)
                    {
                        ThrowUnexpectedTokenException(ref token);
                    }
                    mState = mReadingValueState;
                    break;
                }

                case State.ExpectingCommaOrEndOfObject:
                {
                    if (token.Type == JsonTokenType.Comma)
                    {
                        mState = State.ReadingObjectKey;
                        break;
                    }

                    if (token.Type == JsonTokenType.RBracket)
                    {
                        mState = mStateStack.Pop();
                        if (mState == State.Start)
                        {
                            mCompletedLogMessages.Add(mLogMessage);
                        }
                        break;
                    }

                    ThrowUnexpectedTokenException(ref token);
                    break;
                }

                case State.ReadingTimestampValue:
                {
                    if (token.Type != JsonTokenType.String)
                    {
                        ThrowUnexpectedTokenException(ref token);
                    }
                    if (!DateTimeOffset.TryParseExact(token.Token, TimestampFormat, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out var timestamp))
                    {
                        throw new JsonMessageReaderException(token.LineNumber, token.Position, $"The timestamp ({token.Token}) does not have the expected format.");
                    }
                    mLogMessage.Timestamp = timestamp;
                    mState = State.ExpectingCommaOrEndOfObject;
                    break;
                }

                case State.ReadingHighPrecisionTimestampValue:
                {
                    if (token.Type != JsonTokenType.Number)
                    {
                        ThrowUnexpectedTokenException(ref token);
                    }
                    if (!long.TryParse(token.Token, out long timestamp))
                    {
                        throw new JsonMessageReaderException(
                                  token.LineNumber,
                                  token.Position,
                                  $"The high precision timestamp ({token.Token}) does not have the expected format.");
                    }

                    mLogMessage.HighPrecisionTimestamp = timestamp;
                    mState = State.ExpectingCommaOrEndOfObject;
                    break;
                }

                case State.ReadingLogWriterValue:
                {
                    if (token.Type != JsonTokenType.String)
                    {
                        ThrowUnexpectedTokenException(ref token);
                    }
                    mLogMessage.LogWriterName = token.Token;
                    mState = State.ExpectingCommaOrEndOfObject;
                    break;
                }

                case State.ReadingLogLevelValue:
                {
                    if (token.Type != JsonTokenType.String)
                    {
                        ThrowUnexpectedTokenException(ref token);
                    }
                    mLogMessage.LogLevelName = token.Token;
                    mState = State.ExpectingCommaOrEndOfObject;
                    break;
                }

                case State.ReadingTagsValue:
                {
                    if (token.Type != JsonTokenType.LSquareBracket)
                    {
                        ThrowUnexpectedTokenException(ref token);
                    }
                    mLogMessage.Tags = new TagSet();
                    mState           = State.ReadingTagsValueFirstElement;
                    break;
                }

                case State.ReadingTagsValueFirstElement:
                {
                    if (token.Type == JsonTokenType.RSquareBracket)
                    {
                        // end of tags array
                        mState = State.ExpectingCommaOrEndOfObject;
                        break;
                    }

                    if (token.Type == JsonTokenType.String)
                    {
                        // a tag
                        mLogMessage.Tags += token.Token;
                        mState            = State.ReadingTagsValueElementDelimiter;
                        break;
                    }

                    ThrowUnexpectedTokenException(ref token);
                    break;
                }

                case State.ReadingTagsValueElementDelimiter:
                {
                    if (token.Type == JsonTokenType.RSquareBracket)
                    {
                        // end of tags array
                        mState = State.ExpectingCommaOrEndOfObject;
                        break;
                    }

                    if (token.Type == JsonTokenType.Comma)
                    {
                        mState = State.ReadingTagsValueSubsequentElement;
                        break;
                    }

                    ThrowUnexpectedTokenException(ref token);
                    break;
                }

                case State.ReadingTagsValueSubsequentElement:
                {
                    if (token.Type == JsonTokenType.String)
                    {
                        // a tag
                        mLogMessage.Tags += token.Token;
                        mState            = State.ReadingTagsValueElementDelimiter;
                        break;
                    }

                    ThrowUnexpectedTokenException(ref token);
                    break;
                }

                case State.ReadingApplicationNameValue:
                {
                    if (token.Type != JsonTokenType.String)
                    {
                        ThrowUnexpectedTokenException(ref token);
                    }
                    mLogMessage.ApplicationName = token.Token;
                    mState = State.ExpectingCommaOrEndOfObject;
                    break;
                }

                case State.ReadingProcessNameValue:
                {
                    if (token.Type != JsonTokenType.String)
                    {
                        ThrowUnexpectedTokenException(ref token);
                    }
                    mLogMessage.ProcessName = token.Token;
                    mState = State.ExpectingCommaOrEndOfObject;
                    break;
                }

                case State.ReadingProcessIdValue:
                {
                    if (token.Type != JsonTokenType.Number)
                    {
                        ThrowUnexpectedTokenException(ref token);
                    }
                    if (!int.TryParse(token.Token, out int id))
                    {
                        throw new JsonMessageReaderException(token.LineNumber, token.Position, $"The process id ({token.Token}) does not have the expected format.");
                    }
                    mLogMessage.ProcessId = id;
                    mState = State.ExpectingCommaOrEndOfObject;
                    break;
                }

                case State.ReadingTextValue:
                {
                    if (token.Type != JsonTokenType.String)
                    {
                        ThrowUnexpectedTokenException(ref token);
                    }
                    mLogMessage.Text = token.Token;
                    mState           = State.ExpectingCommaOrEndOfObject;
                    break;
                }

                default:
                    throw new NotImplementedException();
                }
            }

            return(mCompletedLogMessages.ToArray());
        }