/// <summary> /// Serializes counter (metric) data to the stream. /// </summary> /// <param name="stream">Stream to which data should be serialized. Stream should be writable and provide random access.</param> /// <param name="metricData">Collection of metric data to be serialized.</param> public void Serialize(Stream stream, IEnumerable <IReadOnlyMetric> metricData) { if (!stream.CanWrite || !stream.CanSeek) { throw new ArgumentException("Stream should be writable and provide random access.", nameof(stream)); } try { using (var writer = new NoCloseBinaryWriter(stream, Encoding.UTF8)) { var startStreamPosition = stream.Position; // Write version and type serializers info writer.Write(this.version); long crcOffSet = 0; long crcBodyOffSet = 0; if (this.version >= 5) { // Add CRC crcOffSet = stream.Position; writer.Write((uint)0); crcBodyOffSet = stream.Position; } writer.Write(TypeSerializerFlags); // Reserve place to write type serializers data sections offsets var offsetsPosition = stream.Position; stream.Position += 2 * sizeof(long); // Write metrics data this.WriteMetricsData(writer, metricData); // Write cached metrics metadata and offset var serializerDataPosition = stream.Position; stream.Position = offsetsPosition; writer.Write(serializerDataPosition - startStreamPosition); offsetsPosition = stream.Position; stream.Position = serializerDataPosition; SerializationUtils.WriteUInt32AsBase128(writer, (uint)this.metadatas.Count); this.metadatas.ForEach(m => this.WriteMetricMetadata(writer, m)); // Write cached strings and offset serializerDataPosition = stream.Position; stream.Position = offsetsPosition; writer.Write(serializerDataPosition - startStreamPosition); stream.Position = serializerDataPosition; SerializationUtils.WriteUInt32AsBase128(writer, (uint)this.strings.Count); this.strings.ForEach(writer.Write); var endOfStream = stream.Position; if (this.version >= 5) { stream.Position = crcBodyOffSet; var crc = Crc.ComputeCrc(0, stream, stream.Length - crcBodyOffSet); stream.Position = crcOffSet; writer.Write(crc); } stream.Position = endOfStream; } } catch (IOException ioException) { throw new MetricSerializationException("Failed to serialize data.", ioException); } finally { this.nextStringIndex = 0; this.stringIndexes.Clear(); this.strings.Clear(); this.nextMetadataIndex = 0; this.metadataIndexes.Clear(); this.metadatas.Clear(); this.currentMetricDataBlockSize = 0; this.currentMetadataDictionaryBlockSize = 0; this.currentStringDictionaryBlockSize = 0; } }