FrameStreamOutput.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /*
  2. * Copyright (c) 2014,2019 by Farsight Security, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package dnstap
  17. import (
  18. "io"
  19. "os"
  20. )
  21. // FrameStreamOutput implements a dnstap Output to an io.Writer.
  22. type FrameStreamOutput struct {
  23. outputChannel chan []byte
  24. wait chan bool
  25. w Writer
  26. log Logger
  27. }
  28. // NewFrameStreamOutput creates a FrameStreamOutput writing dnstap data to
  29. // the given io.Writer.
  30. func NewFrameStreamOutput(w io.Writer) (o *FrameStreamOutput, err error) {
  31. ow, err := NewWriter(w, nil)
  32. if err != nil {
  33. return nil, err
  34. }
  35. return &FrameStreamOutput{
  36. outputChannel: make(chan []byte, outputChannelSize),
  37. wait: make(chan bool),
  38. w: ow,
  39. log: nullLogger{},
  40. }, nil
  41. }
  42. // NewFrameStreamOutputFromFilename creates a file with the name fname,
  43. // truncates it if it exists, and returns a FrameStreamOutput writing to
  44. // the newly created or truncated file.
  45. func NewFrameStreamOutputFromFilename(fname string) (o *FrameStreamOutput, err error) {
  46. if fname == "" || fname == "-" {
  47. return NewFrameStreamOutput(os.Stdout)
  48. }
  49. w, err := os.Create(fname)
  50. if err != nil {
  51. return
  52. }
  53. return NewFrameStreamOutput(w)
  54. }
  55. // SetLogger sets an alternate logger for the FrameStreamOutput. The default
  56. // is no logging.
  57. func (o *FrameStreamOutput) SetLogger(logger Logger) {
  58. o.log = logger
  59. }
  60. // GetOutputChannel returns the channel on which the FrameStreamOutput accepts
  61. // data.
  62. //
  63. // GetOutputData satisfies the dnstap Output interface.
  64. func (o *FrameStreamOutput) GetOutputChannel() chan []byte {
  65. return o.outputChannel
  66. }
  67. // RunOutputLoop processes data received on the channel returned by
  68. // GetOutputChannel, returning after the CLose method is called.
  69. // If there is an error writing to the Output's writer, RunOutputLoop()
  70. // returns, logging an error if a logger is configured with SetLogger()
  71. //
  72. // RunOutputLoop satisfies the dnstap Output interface.
  73. func (o *FrameStreamOutput) RunOutputLoop() {
  74. for frame := range o.outputChannel {
  75. if _, err := o.w.WriteFrame(frame); err != nil {
  76. o.log.Printf("FrameStreamOutput: Write error: %v, returning", err)
  77. close(o.wait)
  78. return
  79. }
  80. }
  81. close(o.wait)
  82. }
  83. // Close closes the channel returned from GetOutputChannel, and flushes
  84. // all pending output.
  85. //
  86. // Close satisifies the dnstap Output interface.
  87. func (o *FrameStreamOutput) Close() {
  88. close(o.outputChannel)
  89. <-o.wait
  90. o.w.Close()
  91. }