github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekalog/encoder_console.go (about)

     1  // Copyright © 2020-2021. All rights reserved.
     2  // Author: Ilya Stroy.
     3  // Contacts: iyuryevich@pm.me, https://github.com/qioalice
     4  // License: https://opensource.org/licenses/MIT
     5  
     6  package ekalog
     7  
     8  import (
     9  	"io"
    10  	"strings"
    11  
    12  	"github.com/qioalice/ekago/v3/internal/ekaletter"
    13  )
    14  
    15  //noinspection GoSnakeCaseUsage
    16  type (
    17  	// CI_ConsoleEncoder is a type that built to be used as a part of CommonIntegrator
    18  	// as an log Entry encoder to the TTY (console) with human readable format,
    19  	// custom format supporting and ability to enable coloring.
    20  	//
    21  	// If you want to use CI_ConsoleEncoder, you need to instantiate object,
    22  	// set log's text format string (if you dont want to use default one)
    23  	// using SetFormat() and that is.
    24  	// The last thing you need to do is to register CI_ConsoleEncoder with
    25  	// CommonIntegrator using CommonIntegrator.WithEncoder().
    26  	//
    27  	// See SetFormat() docs to figure out how you can manage the log format.
    28  	//
    29  	// CI_ConsoleEncoder may look like heavy rock and it's only half true.
    30  	// It's really flexible customizable text encoder, but the format string parsing
    31  	// is performed only once. At the registration of CI_ConsoleEncoder.
    32  	// Encode operations will be performed over split and parsed format string,
    33  	// and it's as blazing fast as it's even possible.
    34  	//
    35  	// You MUST NOT to call EncodeEntry() method manually.
    36  	// It is used by associated CommonIntegrator and it WILL lead to UB
    37  	// if you will try to use it manually. May even panic.
    38  	CI_ConsoleEncoder struct {
    39  
    40  		// RAW FORMAT
    41  		// This is what user is set by SetFormat() method.
    42  		//
    43  		// It will be parsed, converted and casted to internal structures
    44  		// that are more convenient to be used as source of log message format
    45  		// generator.
    46  		format string
    47  
    48  		// BUILT FORMAT
    49  		// This part represents parsed raw format string.
    50  		//
    51  		// First of all RAW format string parsed to the two group of entities:
    52  		// - Just string, not verb (writes as is),
    53  		// - Format verbs (will be substituted to the log's parts, such as
    54  		//   log's message, timestamp, log's level, log's fields, stacktrace, etc).
    55  		//
    56  		// These parts (w/o reallocation) will be stored with the same sequence
    57  		// as they represented in 'format' but there will be specified verb's types also.
    58  		// Moreover their common length will be calculated and stored to decrease
    59  		// destination []byte buffer reallocations (just allocate big buffer,
    60  		// at least as more as 'formatParts' required).
    61  		formatParts []_CICE_FormatPart
    62  
    63  		colorMap    map[Level]string // map of default colors for each level
    64  		colorMapMax int              // max used len of ASCII color encoded seq.
    65  
    66  		// Sum of: len of just text parts + predicted len of log's parts.
    67  		minimumBufferLen int
    68  
    69  		ff _CICE_FieldsFormat     // parts of fields formatting
    70  		bf _CICE_BodyFormat       // parts of body formatting
    71  		cf _CICE_CallerFormat     // parts of caller, stacktrace's frames formatting
    72  		sf _CICE_StacktraceFormat // parts of stacktrace formatting
    73  		ef _CICE_ErrorFormat      // parts of attached error formatting
    74  
    75  		preEncodedFields        []byte
    76  		preEncodedFieldsWritten int16
    77  	}
    78  )
    79  
    80  var (
    81  	// Make sure we won't break API.
    82  	_ CI_Encoder = (*CI_ConsoleEncoder)(nil)
    83  )
    84  
    85  // SetFormat allows you to set format string that will be used as a template
    86  // to generate and represent all log Entry objects.
    87  //
    88  // Calling this method many times will overwrite previous value of format string.
    89  //
    90  // The format string will be parsed and applied only after CI_ConsoleEncoder
    91  // is registered with CommonIntegrator using CommonIntegrator.WithEncoder() method.
    92  // After it is done, the format string cannot be changed and this method has no-op.
    93  //
    94  // -----
    95  //
    96  // Attached ekaerr.Error.
    97  //
    98  // You know that you may log ekaerr.Error objects using special log finishers,
    99  // like Logger.Errore(), Logger.Warne(), etc.
   100  // According the main rule and purpose of ekaerr packages,
   101  // the attached fields are associated with its stackframe.
   102  // So, fields of a some stackframe will be placed exactly near related stackframe.
   103  // You can't write them all at the one place.
   104  // Read more below about verbs to recognize how you can manage the output.
   105  //
   106  // -----
   107  //
   108  // Verbs. Introduction.
   109  //
   110  // The format string has its own verbs and verbs' parameters using which
   111  // you can manage the place and view of Entry's parts.
   112  //
   113  // All verbs has the following format:
   114  // "{{<verb_name>/<verb_parameter_1>/.../<verb_parameter_N>}}"
   115  //
   116  // You should build your own format string using verbs, separators, text, etc.
   117  //
   118  // For each verb there's verb name and its short aliases, so you can use any of that.
   119  // Each verb has its own parameters and its defaults.
   120  // You can overwrite one, two, N or all default verb parameters.
   121  //
   122  // The order of verb parameters doesn't matter.
   123  // Letter case of verb names or its parameter names doesn't matter.
   124  //
   125  // Below you can see the verbs and its parameters.
   126  // Keep in mind, that each verb's parameter has its own key,
   127  // that determines what this verb parameter is.
   128  //
   129  // Verbs. List.
   130  //
   131  // 0. Empty verb / incorrect verb.
   132  //    All text that is not verb or an incorrect verb will be used as is.
   133  //    It will be a part of final log message.
   134  //
   135  // 1. Entry.Level verb.
   136  //    Names: "level", "lvl", "l".
   137  //
   138  //    The verb will be replaced by Entry.Level string representation.
   139  //    By default it writes a full Level's capitalized name.
   140  //    The same as is returned by Level.String().
   141  //
   142  //    Parameters:
   143  //    (Only first parameter is supported. 2nd and next will be ignored.
   144  //    Incorrect parameter will be ignored.)
   145  //
   146  //    - "d", "D": Write Level's number instead of string.
   147  //      From "0" for LEVEL_EMERGENCY down to "7" for LEVEL_DEBUG.
   148  //    - "s": Write Level's short string variant.
   149  //      The same as is returned by Level.String3().
   150  //      Examples: "Emerg", "Ale", "Cri", "Err", "War", "Noe", "Inf", "Deb".
   151  //    - "S": Write Level's short upper-cased string variant.
   152  //      The same as is returned by Level.ToUpper3().
   153  //      Examples: "EMERG", "ALE", "CRI", "ERR", "WAR", "NOE", "INF", "DEB".
   154  //    - "ss": Write Level's full string variant.
   155  //      This is default verb parameter. The same as is returned by Level.String().
   156  //    - "SS": Write Level's full upper-cased string variant.
   157  //      The same as is returned by Level.ToUpper().
   158  //      Examples: "EMERGENCY", "ALERT", "CRITICAL", "WARNING", etc.
   159  //
   160  // 2. Entry.Time verb.
   161  //    Names: "time", "t".
   162  //
   163  //    The verb will be replaced by Entry.Time string representation.
   164  //    Default time format is: "Mon, Jan 02 15:04:05".
   165  //
   166  //    Parameters:
   167  //    (Only first parameter is supported. 2nd and next will be ignored.
   168  //    Incorrect parameter will be ignored.)
   169  //
   170  //    - "UNIX", "TIMESTAMP": Write time.Time as unix timestamp in seconds.
   171  //      Example: 1619549194 for Tue Apr 27 2021 18:46:34 GMT+0000
   172  //    - "ANSIC": Write time.Time as time.ANSIC format.
   173  //      Example: "Mon Jan _2 15:04:05 2006".
   174  //    - "UNIXDATE", "UNIX_DATE": Write time.Time as time.UnixDate format.
   175  //      Example: "Mon Jan _2 15:04:05 MST 2006".
   176  //    - "RUBYDATE", "RUBY_DATE": Write time.Time as time.RubyDate format.
   177  //      Example: "Mon Jan 02 15:04:05 -0700 2006".
   178  //    - "RFC822": Write time.Time as time.RFC822 format.
   179  //      Example: "02 Jan 06 15:04 MST".
   180  //    - "RFC822Z": Write time.Time as time.RFC822Z format.
   181  //      Example: "02 Jan 06 15:04 -0700".
   182  //    - "RFC850": Write time.Time as time.RFC850 format.
   183  //      Example: "Monday, 02-Jan-06 15:04:05 MST".
   184  //    - "RFC1123": Write time.Time as time.RFC1123 format.
   185  //      Example: "Mon, 02 Jan 2006 15:04:05 MST".
   186  //    - "RFC1123Z": Write time.Time as time.RFC1123Z format.
   187  //      Example: "Mon, 02 Jan 2006 15:04:05 -0700".
   188  //    - "RFC3339": Write time.Time as time.RFC3339 format.
   189  //      Example: "2006-01-02T15:04:05Z07:00".
   190  //    - "<your_own_time_format>: Uses string as time format.
   191  //      time.Time.Format() will be called with that format string.
   192  //
   193  // 3. Entry's log body verb.
   194  //    Names: "message", "body", "m", "b".
   195  //
   196  //    The verb will be replaced by Entry's log message.
   197  //    You can include this verb only once.
   198  //    2nd and next these verbs will be treated as just a text.
   199  //
   200  //    Parameters:
   201  //    (The same key parameters will be overwritten by the last one.
   202  //    The parsing of parameters will be stopped when an incorrect parameter found).
   203  //
   204  //    - "?^<text>": Places <text> before log's body if body is not empty.
   205  //    - "?$<text>": Places <text> after log's body if body is not empty.
   206  //
   207  // 4. Entry's caller verb.
   208  //    Names: "caller", "who", "w".
   209  //
   210  //    The verb will be replaced by caller's info.
   211  //    It may include a package, function, line number of the caller.
   212  //    The caller is the function that calls a log finisher.
   213  //
   214  //    Parameters:
   215  //    (The same key parameters will be overwritten by the last one.
   216  //    The parsing of parameters will be stopped when an incorrect parameter found).
   217  //
   218  //    - "0": Do not include caller's info.
   219  //      It's meaningless by the first view, but the main purpose of that verb is
   220  //      the fact that you can specify format using "f<format>" verb parameter,
   221  //      that also will be used as a stacktrace's format.
   222  //      So, if you want to specify format for stacktrace,
   223  //      but don't want to include caller's info you need this verb's parameter.
   224  //    - "f<format>", "F<format>": You can specify format of caller string,
   225  //      that will be used as template to generate both of caller's info and stacktrace.
   226  //      <format> string must be combined by your own way with:
   227  //      - "w": Short function name. Only function, without package path.
   228  //      - "W": Full function name. Includes package path.
   229  //      - "f": Short filename. Only filename, without full path to that file.
   230  //      - "F": Full filename. Includes full path to that file.
   231  //      - "l", "L": File's line number.
   232  //      - "p", "P": Full package path.
   233  //      - <any_other>: Writes as is. Useful to split format's parts.
   234  //
   235  //    Example: "{{w/0/fF:L}}" is a caller's verb, that specifies format
   236  //    "<full_file_name>:<line_number>" for both of caller and stacktrace,
   237  //    but caller info won't be included to the log's output.
   238  //
   239  // 5. Entry's stacktrace verb.
   240  //    Names: "stacktrace", "s".
   241  //
   242  //    The verb will be replaced by stacktrace, if it's presented.
   243  //    Each stack frame may include its package, function, line number.
   244  //
   245  //    WARNING.
   246  //    If you won't add this verb, the fields of your attached ekaerr.Error
   247  //    won't be encoded, because they are heavily linked with stacktrace!
   248  //
   249  //    Parameters:
   250  //    (The same key parameters will be overwritten by the last one.
   251  //    The parsing of parameters will be stopped when an incorrect parameter found).
   252  //
   253  //    - "?^<text>": Places <text> before stacktrace if stacktrace is presented.
   254  //    - "?$<text>": Places <text> after stacktrace if stacktrace is presented.
   255  //
   256  // 6. Entry's fields verb.
   257  //    Names: "fields", "f".
   258  //
   259  //    The verb will be replaced by log Entry's fields.
   260  //    Keep in mind, this verb has an affect only for log's fields.
   261  //    If you have attached ekaerr.Error, its fields will be printed if
   262  //    stacktrace's verb is included. But this verb has an affect of format
   263  //    to that fields also.
   264  //
   265  //    Parameters:
   266  //    (The same key parameters will be overwritten by the last one.
   267  //    The parsing of parameters will be stopped when an incorrect parameter found).
   268  //
   269  //    - "?^<text>": Places <text> before FIRST field (in stackframe).
   270  //    - "?$<text>": Places <text> after LAST field (in stackframe).
   271  //    - "k<text>": Places <text> before EACH field's key.
   272  //    - "v<text>": Places <text> before EACH field's value.
   273  //    - "e<text>": Places <text> after EACH field's value (last field excluded).
   274  //    - "l<text>": Places <text> at the each new line of log Entry's fields part.
   275  //    - "le<text>": Places <text> at the each new line of attached ekaerr.Error fields part.
   276  //    - "*<number>": <number> is how much fields are placed at the one line.
   277  //      (By default: 4. Use <= 0 value to place all fields at the one line).
   278  //
   279  // 7. TTY coloring verb.
   280  //    Names: "color", "c".
   281  //
   282  //    This verb allows you to make some parts of final messages be colored.
   283  //    Color in a TTY terms is just a special escape sequence.
   284  //    Think about this verb as a HTML tag.
   285  //
   286  //    First of all, if you're placing this verb of starting coloring,
   287  //    you need to place the verb of ending coloring.
   288  //    Otherwise all next data will be colored too until next color verb is found.
   289  //    It's not about CI_ConsoleEncoder but about how TTY coloring works.
   290  //
   291  //    Next thing you need to know is
   292  //    There's "default" colors for each log's Level.
   293  //    If you don't present a color using verb's parameters,
   294  //    the default log's level color will be used.
   295  //    You can overwrite default colors for level using SetColorFor() method.
   296  //
   297  //    How parameters works.
   298  //    All parameters are split to its groups:
   299  //    - Bold (enable/disable),
   300  //    - Italic (enable/disable),
   301  //    - Underline (enable/disable),
   302  //    - Background color (overwrite/disable),
   303  //    - Foreground color (overwrite/disable),
   304  //    - Cancel any color.
   305  //    You may specify more than 1 parameter to combine them.
   306  //    If you specify more then 1 parameter for the same group, the last one will be used.
   307  //    If you specify "cancel any color" parameter, all others parameters will be ignored.
   308  //    If any parameter is invalid, all others will be ignored.
   309  //
   310  //    To specify color, you can use:
   311  //    - ASCII colors: Use "ascii<color>" or "ascii(<color>)" syntax.
   312  //      Allowable colors: [30..37]+[90..97] for foreground,
   313  //      [40..47]+[100..107] for background.
   314  //      Read more: https://en.wikipedia.org/wiki/ANSI_escape_code
   315  //      It's UB to specify foreground color for background and vice-versa.
   316  //      (Most likely ASCII affiliation of color will be used).
   317  //    - X256 colors: Use "<color>" syntax. Allowable colors: [0..255].
   318  //      Read more using the link above.
   319  //    - HEX colors: Use "#<color>" format. Will be transformed to X256 colors.
   320  //      Read more: https://en.wikipedia.org/wiki/Web_colors
   321  //    - RGB colors: Use "rgb:<red>,<green>,<blue>" or "rgb(<red>,<green>,<blue>)"
   322  //      or "rgb,<red>,<green>,<blue>" syntax.
   323  //      All of <red>, <green>, <blue> must be in range [0..255].
   324  //      Will be transformed to X256 colors.
   325  //      Read more using link above.
   326  //    - "-1": Disable coloring for desired type (background/foreground).
   327  //
   328  //    Parameters:
   329  //
   330  //    - No parameters: Uses log's Level default color.
   331  //    - "0": Disables all TTY font effects: color, bold, italic, underline.
   332  //    - "bold", "b": Use bold font.
   333  //    - "nobold", "nob": Disable bold font, return back to normal.
   334  //    - "italic", "i": Use italic font.
   335  //    - "noitalic", "noi": Disable italic font, return back to normal.
   336  //    - "underline", "u": Use underline font.
   337  //    - "nounderline", "nou": Disable underline font, return back to normal.
   338  //    - "fg:<color>: Set <color> for text's foreground. See above about colors.
   339  //    - "bg:<color>": Set <color> for text's background. See above about colors.
   340  //
   341  //   Reminder.
   342  //   Make sure your terminal supports X256 colors or use ASCII colors otherwise.
   343  //   If your terminal doesn't support X256 colors and you will try to use it,
   344  //   you may get an ugly escape sequences in your output.
   345  //
   346  //   Dropping colors for specific io.Writer.
   347  //   You may want to disable coloring for specific io.Writer leaving it for another.
   348  //   See CICE_DropColors() for more details.
   349  //
   350  // -----
   351  //
   352  // If you won't set any format string, the default one will be used.
   353  // It is:
   354  //
   355  //   "{{c}}{{l}} {{t}}{{c/0}}\n" +      // include colored level, colored time
   356  //   "{{m/?$\n}}" +                     // include message with \n if non-empty
   357  //   "{{f/?$\n/v = /e, /l\t/le\t\t}}" + // include fields with " = " as key-value separator
   358  //   "{{s/?$\n/e, }}" +                 // include stacktrace with \n if non-empty
   359  //   "{{w/0/fd}}" +                     // omit caller, specify each stacktrace's frame format
   360  //   "\n"
   361  //
   362  func (ce *CI_ConsoleEncoder) SetFormat(newFormat string) *CI_ConsoleEncoder {
   363  
   364  	if s := strings.TrimSpace(newFormat); s == "" {
   365  		// Just check whether 'newFormat' is non-empty string or a string
   366  		// that contains not only whitespace characters. But do not ignore them.
   367  		return ce
   368  	}
   369  
   370  	ce.format = newFormat
   371  	return ce
   372  }
   373  
   374  // SetColorFor sets color what will be used as a replace for level-depended
   375  // color verb from the 'format' string that is set by SetFormat() func
   376  //
   377  // Example: "c/fg:ascii:31/b", "c/fg:#123456/bg:rgb,50,50,50/i/u".
   378  func (ce *CI_ConsoleEncoder) SetColorFor(level Level, color string) *CI_ConsoleEncoder {
   379  
   380  	if ce.colorMap == nil {
   381  		ce.colorMap = make(map[Level]string)
   382  	}
   383  
   384  	if encodedColor := ce.rvColorHelper(color); encodedColor != "" {
   385  		ce.colorMap[level] = encodedColor
   386  		if l := len(encodedColor); ce.colorMapMax < l {
   387  			ce.colorMapMax = l
   388  		}
   389  	}
   390  
   391  	return ce
   392  }
   393  
   394  // PreEncodeField allows you to pre-encode some ekaletter.LetterField,
   395  // that is must be used with EACH Entry that will be encoded using this CI_ConsoleEncoder.
   396  //
   397  // It's useful when you want some unchanged runtime data for each log message,
   398  // like git hash commit, version, etc. Or if you want to create many loggers
   399  // attach some different fields to them and log different logs using them.
   400  //
   401  // Unnamed fields are not allowed.
   402  //
   403  // WARNING!
   404  // PreEncodeField() MUST BE USED ONLY IF CI_ConsoleEncoder HAS BEEN REGISTERED
   405  // WITH SOME CommonIntegrator ALREADY. UB OTHERWISE, MAY PANIC!
   406  func (ce *CI_ConsoleEncoder) PreEncodeField(f ekaletter.LetterField) {
   407  
   408  	// Avoid calls of PreEncodeField() when CI_ConsoleEncoder has not built yet.
   409  	if f.Key == "" || len(ce.formatParts) == 0 || f.IsInvalid() ||
   410  		f.RemoveVary() && f.IsZero() {
   411  		return
   412  	}
   413  
   414  	preEncodedFieldsLenBak := len(ce.preEncodedFields)
   415  	ce.preEncodedFields = ce.encodeField(ce.preEncodedFields, f, false, ce.preEncodedFieldsWritten)
   416  
   417  	if len(ce.preEncodedFields) != preEncodedFieldsLenBak {
   418  		ce.preEncodedFieldsWritten++
   419  	}
   420  }
   421  
   422  // EncodeEntry encodes passed Entry as text using provided (and parsed)
   423  // format string that is set by SetFormat() method, returning a RAW encoded data.
   424  //
   425  // It may includes a special ASCII escape sequences to color output.
   426  // It's enabled by default (if you didn't change format string).
   427  //
   428  // EncodeEntry is for internal purposes only and MUST NOT be called directly.
   429  // UB otherwise, may panic.
   430  func (ce *CI_ConsoleEncoder) EncodeEntry(e *Entry) []byte {
   431  
   432  	// TODO: Reuse allocated buffers
   433  
   434  	to := make([]byte, 0, ce.minimumBufferLen)
   435  
   436  	// Use last ekaerr.Error's message as Entry's one if it's empty.
   437  	if e.ErrLetter != nil {
   438  		if l := len(e.ErrLetter.Messages); l > 0 && e.LogLetter.Messages[0].Body == "" {
   439  			e.LogLetter.Messages[0].Body = e.ErrLetter.Messages[l-1].Body
   440  			e.ErrLetter.Messages[l-1].Body = ""
   441  		}
   442  	}
   443  
   444  	for _, part := range ce.formatParts {
   445  		switch part.typ.Type() {
   446  
   447  		case _CICE_FPT_VERB_JUST_TEXT:
   448  			to = ce.encodeJustText(to, part)
   449  		case _CICE_FPT_VERB_COLOR_CUSTOM:
   450  			to = ce.encodeColor(to, part)
   451  		case _CICE_FPT_VERB_COLOR_FOR_LEVEL:
   452  			to = ce.encodeColorForLevel(to, e)
   453  		case _CICE_FPT_VERB_BODY:
   454  			to = ce.encodeBody(to, e)
   455  		case _CICE_FPT_VERB_TIME:
   456  			to = ce.encodeTime(e, part, to)
   457  		case _CICE_FPT_VERB_LEVEL:
   458  			to = ce.encodeLevel(to, part, e)
   459  		case _CICE_FPT_VERB_STACKTRACE:
   460  			to = ce.encodeStacktrace(to, e)
   461  		case _CICE_FPT_VERB_CALLER:
   462  			to = ce.encodeCaller(to, e)
   463  
   464  		case _CICE_FPT_VERB_FIELDS:
   465  			errLetterSystemFields := []ekaletter.LetterField(nil)
   466  			if e.ErrLetter != nil {
   467  				errLetterSystemFields = e.ErrLetter.SystemFields
   468  			}
   469  			to = ce.encodeFields(to, e.LogLetter.SystemFields, errLetterSystemFields, false, false)
   470  
   471  			// Handle special case when ekaerr.Error's ekaletter.Letter has a fields
   472  			// but has no stacktrace. It means that lightweight error has been created.
   473  			lightweightErrorFields := []ekaletter.LetterField(nil)
   474  			if e.ErrLetter != nil && len(e.ErrLetter.StackTrace) == 0 && len(e.ErrLetter.Fields) > 0 {
   475  				lightweightErrorFields = e.ErrLetter.Fields
   476  			}
   477  			to = ce.encodeFields(to, e.LogLetter.Fields, lightweightErrorFields, false, true)
   478  		}
   479  	}
   480  
   481  	// Restore ekaerr.Error's last message that was used as Entry's message.
   482  	if e.ErrLetter != nil {
   483  		if l := len(e.ErrLetter.Messages); l > 0 && e.ErrLetter.Messages[l-1].Body == "" {
   484  			e.ErrLetter.Messages[l-1].Body = e.LogLetter.Messages[0].Body
   485  			e.LogLetter.Messages[0].Body = ""
   486  		}
   487  	}
   488  
   489  	return to
   490  }
   491  
   492  // CICE_DropColors returns an io.Writer, you can write a data with TTY colors to,
   493  // that will rewrite everything but colors to the your dest io.Writer.
   494  //
   495  // You can pass returned io.Writer to the CommonIntegrator.WriteTo()
   496  // method associating it with the CI_ConsoleEncoder that writes a log messages
   497  // with a TTY colors. Returned io.Writer will rewrite message to your io.Writer
   498  // but without these shell color sequences.
   499  //
   500  // It's useful when you want to write colored log messages to TTY but
   501  // raw to the files. Or any other destination.
   502  //
   503  // Keep in mind, it's not "free" operation. It allocates RAM buffer,
   504  // writes raw data to, parses it, droppings colors and rewrites cleared raw data.
   505  func CICE_DropColors(dest io.Writer) io.Writer {
   506  	return &_CICE_DropColors{dest: dest}
   507  }